linux-troubleshooting
Systematically isolate, diagnose, and resolve Linux system, storage, memory, performance, and service failures. Use when diagnosing high load, out-of-memory (OOM) crashes, disk space or inode exhausti
Files2
View on GitHubSKILL.mdskills/linux-troubleshooting/SKILL.md
GitHubLinux Troubleshooting and Diagnosis
Effective troubleshooting is driven by evidence, hypothesis testing, and systematic isolation. An agent must never make random configuration changes or reboot systems hoping an issue disappears. Always collect reproducible observations first, form a falsifiable hypothesis, verify the root cause, and then apply a targeted remediation.
Core Rules
- Observe before modifying: Gather logs, metrics, and error codes before changing files, restarting services, or executing remediation commands.
- One change at a time: Test a single isolated variable. If a modification does not resolve the issue, revert it before attempting another.
- Check the basics first: Disk space, inode exhaustion, memory pressure (OOM), permissions, time, DNS, and a recent change are the most common causes; rule them out before exotic hypotheses.
- Preserve crash evidence: Copy relevant log excerpts, core dumps, or kernel messages before clearing caches or restarting services.
- Never run destructive or state-changing commands blindly: Avoid
rm -rf,reboot,kill -9on unknown processes,chmod -R, dropping caches, or editing production config without identifying the target, stating the effect, and getting the user's approval on a production host. - Diagnose read-only first; escalate privilege only when a command needs it. Prefer
journalctl,ss,df,/procreads. Usesudofor a specific command, not a root shell; show the exact sudo command and get approval before running it. - Logs hold secrets and personal data. Redact tokens, passwords, hostnames, and IPs before pasting output into tickets or chats, and do not
catcredential files while looking for "the config". - State the environment. Record distro, kernel (
uname -r), whether it is a VM or container, and systemd vs another init before interpreting output; cgroup, OOM, and journald behavior differ.
1. Quick Triaging Checklist (The 60-Second Scan)
Run these non-destructive diagnostics when an incident begins:
# 1. System Load & Uptime (CPU saturation)
uptime
# 2. Memory & Swap consumption
free -h
# 3. Disk space and mount points
df -h
# 4. Inode exhaustion (disk can be full even with free gigabytes!)
df -i
# 5. Kernel errors & Out-Of-Memory (OOM) killer events
# (dmesg may need root when kernel.dmesg_restrict=1; journalctl -k works for journal readers)
sudo dmesg -T --level=alert,crit,err | tail -n 25
journalctl -k -b -p err --no-pager | tail -n 25
# 6. Failed systemd services
systemctl --failed
2. Diagnosing Common Failure Categories
Category A: Out-Of-Memory (OOM) and Memory Leaks
When processes disappear without a trace or report Killed:
# Check if Linux OOM killer terminated the process
dmesg -T | grep -i -E "killed process|oom_reaper|out of memory"
# Identify top memory-consuming processes
ps aux --sort=-%mem | head -n 10
# Inspect detailed system memory breakdown (buffers, cache, dirty memory)
cat /proc/meminfo | head -n 15
Category B: Disk Full and Inode Exhaustion
- Symptom 1:
No space left on devicedespitedf -hshowing free gigabytes.- Cause: Inode exhaustion (too many tiny files), a quota, or a full filesystem different from the one you checked (
df -h /pathfor the failing path). - Check:
df -i. Count files per top-level directory (read-only):for d in /var /tmp /home; do printf '%s %s\n' "$d" "$(find "$d" -xdev -type f 2>/dev/null | wc -l)"; done du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail -n 10
- Cause: Inode exhaustion (too many tiny files), a quota, or a full filesystem different from the one you checked (
- Symptom 2: Disk space not freed after
rm large_file.log.- Cause: Deleted file is still held open by a running process.
- Check & Fix:
# Find deleted files still held by open file descriptors sudo lsof +L1 # Restart or reload the holding process to release the disk blocks
Category C: High CPU and Load Average
When load average is high:
- High load + high
%cpu= CPU saturation (busy compute loops). - High load + high
%iowait(wa) = Disk I/O bottleneck (slow disks, paging). - High load + low CPU/I/O = Processes blocked on uninterruptible sleep (D-state) or NFS hangs.
# 1-second system activity overview (check 'us', 'sy', 'wa', 'st')
vmstat 1 5
# Check processes in uninterruptible sleep (D state)
ps -eo state,pid,user,wchan:20,cmd | awk '$1 ~ /^D/'
# Pressure stall information (kernel 4.20+ with PSI enabled): is CPU, memory or I/O the bottleneck?
cat /proc/pressure/cpu /proc/pressure/memory /proc/pressure/io
Load average counts runnable tasks plus tasks in uninterruptible sleep, so a high number alone does not mean CPU saturation. Compare against core count (nproc) and look at vmstat columns r, b, wa, st (steal time indicates a noisy virtual host).
Category D: Failing systemd Services
When a service fails to start or crashes repeatedly:
# Inspect status, exit code, and recent unit log lines
systemctl status <service-name>
# View full journal logs for the specific unit since current boot
journalctl -u <service-name> -b --no-pager -n 50
# Exit reason and restart loop evidence (Result=, ExecMainStatus=, NRestarts=)
systemctl show <service-name> -p Result,ExecMainStatus,NRestarts,ActiveEnterTimestamp
# Check service configuration syntax without starting it
systemd-analyze verify /lib/systemd/system/<service-name>.service
More categories (network and DNS, permissions and SELinux, boot problems, containers on a single host, time sync) with decision tables: Triage playbook.
3. Systematic 5-Step Troubleshooting Process
1. Reproduce & Define: What is failing? What is the exact error message?
│
▼
2. Gather Evidence: Inspect journalctl, dmesg, /proc, ss, top, df.
│
▼
3. Formulate Hypothesis: "The database crashed because /var reached 100% capacity."
│
▼
4. Test & Validate: Verify hypothesis with specific command (`df -h /var`).
│
▼
5. Remediate & Confirm: Apply minimal fix, test service, verify stability.
4. Common Mistakes and Anti-Patterns
| Anti-Pattern | Risk | Correct Practice |
|---|---|---|
| Blindly rebooting a failing server | Loses transient logs in memory, does not resolve root cause | Collect journalctl and dmesg before any restart |
rm -rf /var/log/* |
Deletes active log descriptors, fails to release disk space, loses evidence | After saving evidence and with approval, truncate one identified file (: > /var/log/app/huge.log) or use journalctl --vacuum-size= / logrotate |
echo 3 > /proc/sys/vm/drop_caches to "fix" memory |
Only hides cache effects and hurts performance | Read free -h "available", check ps RSS and PSI |
chmod -R 777 to fix permission errors |
Opens the data to every user | Identify the process user (ps -o user), then fix ownership or ACL narrowly |
kill -9 first |
Skips cleanup, corrupts state | systemctl stop / SIGTERM, then escalate with cause known |
| Changing 5 configuration settings at once | Impossible to know which change fixed or exacerbated the bug | Change one setting, test, and document |
| Disabling SELinux/AppArmor permanently | Leaves system insecure | Check audit logs (ausearch -m avc -ts recent) and generate targeted policy rules |
5. Verification Checklist
- Exact error message and timestamp captured.
- Checked disk capacity (
df -h) and inode status (df -i). - Checked OOM events in kernel buffer (
dmesg). - Confirmed root cause before applying configuration changes.
- Validated service recovery with
systemctl is-active <service>. - Documented fix and verified system metrics returned to normal thresholds.