Linux errors and how to fix them
89 error messages and symptoms from real servers. Each answer gives the exact message, what it means, every cause that prints it with a check that proves it and the fix for that cause, how to prevent it, and then a scenario to break and fix it yourself in the playground. Generated from the site's data; the interactive reference adds search by pasted error text.
Files and permissions
Files and permissions
Permission denied when running a script
-bash: ./deploy.sh: Permission denied
What it means
The shell asked the kernel to run deploy.sh as a program and the kernel said no. For ./name that needs three things: an execute bit on the file, a mount that allows running programs, and search (x) permission on every directory on the way. You own the file, so ownership is not the problem.
Causes, most likely first
The file has no execute bit (
-rw-r--r--). Without x, the kernel refuses to run it as a program, whoever owns it.Check
ls -l deploy.sh # no x in the mode (-rw-r--r--): this is your causeFix
chmod u+x deploy.sh(or 755 if others run it too).The file system is mounted noexec (a hardened /tmp or /home often is). noexec forbids running any program from that mount, even one with the x bit.
Check
findmnt -no OPTIONS --target deploy.sh # noexec in the list: the mount forbids itFix
Keep scripts where execution is allowed (/usr/local/bin, /opt).
bash deploy.shworks, but it sidesteps a policy someone set on purpose.A directory on the path is not searchable for you. Without x on a directory, nothing inside it can be reached, so the run fails the same way.
Check
namei -l "$PWD/deploy.sh" # a directory without x for you: this is your causeFix
Add x for the group or others on that directory (
chmod o+x DIR), never 777.
Prevent it
Commit scripts with the bit set (git update-index --chmod=+x). Never use 777: it lets anyone rewrite what runs.
Now learn it: break and fix it yourself in Permission denied on a script, then take Level 02 · Permissions and ownership. Open in the interactive reference · Link to this answer
Files and permissions
bad interpreter: No such file or directory
-bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory
What it means
The script's first line (#!, the shebang) names the program that should run it, and the kernel could not find that program. /bin/bash^M shows the name it looked for: ^M is a carriage return, so it looked for a file called "bash" plus an invisible character.
Causes, most likely first
Windows line endings (CRLF). Each line ends in \r\n, so the shebang names
/bin/bash\r, which does not exist.Check
file deploy.sh # with CRLF line terminators: this is your cause head -1 deploy.sh | od -c | head -2 # \r before \n confirms itFix
sed -i 's/\r$//' deploy.sh, ordos2unix deploy.sh(apt or dnf install dos2unix).The shebang names an interpreter that is not installed (python, an old path). The kernel reports the missing interpreter with the same words.
Check
head -1 deploy.sh # the interpreter it asks for command -v bash python3 # no output for that name: it is not installedFix
Install it, or point the shebang at one that exists, such as
#!/usr/bin/env python3.
Prevent it
Add *.sh text eol=lf to .gitattributes, and set your editor to LF for scripts.
Now learn it: break and fix it yourself in bad interpreter: ^M, then take Level 02 · Permissions and ownership. Open in the interactive reference · Link to this answer
Files and permissions
Operation not permitted, even as root
sed: cannot rename /etc/nginx/conf.d/sedXk3pQa: Operation not permitted
What it means
root tried to change a file and the kernel refused with EPERM, "Operation not permitted". Unlike "Permission denied", this is not about modes: something forbids the operation even for root. Here sed wrote a temporary file and could not rename it over the original.
Causes, most likely first
The file has the immutable attribute (chattr +i). An immutable file cannot be changed, renamed over or deleted, by anyone, until the flag is removed.
Check
lsattr /etc/nginx/conf.d/rate-limit.conf # an i in the flags: this is your causeFix
sudo chattr -i FILE, edit it, thensudo chattr +i FILEagain if the lock was intended.The append-only attribute (chattr +a). Appends work, but rewriting, renaming or truncating fails with this error.
Check
lsattr /etc/nginx/conf.d/rate-limit.conf # an a in the flagsFix
sudo chattr -a FILE, make the change, and put the flag back if it was intended.The directory is immutable. Then nothing in it can be created, renamed or removed, so the temporary file or the rename fails.
Check
lsattr -d /etc/nginx/conf.d # an i on the directory itselfFix
sudo chattr -i DIR, make the change, then restore the flag if it was intended.root without the capability: inside a container, or chown on an NFS share exported with root_squash. That root is not the real root, so the kernel or the server says no.
Check
findmnt -no FSTYPE,OPTIONS -T /etc/nginx/conf.d # nfs, proc or sysfs: the file system refuses grep CapEff /proc/self/status # fewer bits than the same line on the host: a restricted rootFix
Make the change where root really has the right: on the host, or on the NFS server.
Prevent it
Document every immutable file; config management should know about them.
Now learn it: break and fix it yourself in Operation not permitted, even as root, then take Level 02 · Permissions and ownership. Open in the interactive reference · Link to this answer
Files and permissions
EACCES: permission denied in a service's log
Error: EACCES: permission denied, open '/srv/shop/uploads/receipt-8813.pdf'
What it means
The service tried to open a file or folder and the kernel said its user may not. EACCES is the kernel's "Permission denied": the process's user, groups, the file's mode, and on Rocky the SELinux label decided against it. The path in quotes is the one it failed on.
Causes, most likely first
Files created by root with sudo (tar, cp, git pull) in the app's folders. They belong to root, so the service user cannot write them.
Check
namei -l /srv/shop/uploads # root-owned parts on the path sudo -u shop test -w /srv/shop/uploads && echo writable # no output: the service user cannot writeFix
sudo chown -R shop:shop /srv/shop/uploads.The service runs as a different user than you think. The modes may be right for the user you expect, not for the one actually running.
Check
systemctl show -p User shop # the user it runs as; empty means root ps -o user= -p $(pgrep -o -f shop) # the user of the running processFix
Give that user access, or set
User=in the unit to the account the files belong to.A secret tightened to root-only that the service reads itself. After
chmod 600the service user can no longer read it.Check
ls -l FILE # -rw------- root root: only root can read itFix
sudo chown root:shop FILE && sudo chmod 640 FILE.On Rocky/RHEL, SELinux denies it. Modes and owners are right, but the file's label does not allow this service's domain.
Check
sudo ausearch -m avc -ts recent # a denial naming the path: this is your causeFix
Relabel with
semanage fcontextandrestorecon(see SELinux denial). Neversetenforce 0.systemd sandboxing (ProtectHome=, ProtectSystem=) hides or locks the path for this service only. It works by hand but not in the service.
Check
systemctl show -p ProtectHome -p ProtectSystem -p ReadWritePaths shop # yes or strict, and the path is not in ReadWritePathsFix
A drop-in with
ReadWritePaths=/srv/shop/uploads, then daemon-reload and restart.
Prevent it
Run deploy steps as the service user (sudo -u shop ...), not as root.
Now learn it: break and fix it yourself in Files owned by root after sudo · A world-readable secrets file, then take Level 02 · Permissions and ownership. Open in the interactive reference · Link to this answer
Files and permissions
403 Forbidden from nginx
HTTP/1.1 403 Forbidden
What it means
nginx found the request but refused to serve it, and the browser got 403 Forbidden. The reason is not on the page: nginx writes it to its error log, and the log line tells you which cause you have. Some pages working means the server is fine; the problem is these files.
Causes, most likely first
The file or a directory on its path is not readable by the web user (www-data on Ubuntu, nginx on Rocky). nginx gets "Permission denied" from the kernel and answers 403.
Check
sudo tail -n 5 /var/log/nginx/error.log # (13: Permission denied): modes or SELinux namei -l /var/www/html/report.html # the first part without r (file) or x (directory) for the web userFix
chmod 644 FILEand 755 for folders.A restrictive umask on the deploy user. New files are created 600 or 640, so only the newest pages fail.
Check
ls -l /var/www/html # new files without r for others umask # as the deploy user: 0077 or 0027Fix
Set
umask 022in the deploy user's profile or deploy tool, and fix the existing files.A directory with no index file while autoindex is off. nginx refuses to list the folder and says 403.
Check
sudo tail -n 5 /var/log/nginx/error.log # directory index of ... is forbidden: this is your causeFix
Add the index file, or fix the
indexdirective.An allow/deny rule in the config matches the client.
Check
sudo tail -n 5 /var/log/nginx/error.log # access forbidden by rule: this is your causeFix
Correct the allow/deny lines, then
sudo nginx -t && sudo systemctl reload nginx.On Rocky/RHEL, an SELinux label. Modes are right, but nginx may only read files labelled for the web.
Check
sudo ausearch -m avc -ts recent # a denial for nginx on that fileFix
Relabel (see SELinux denial).
Prevent it
Deploy with a known umask, and test a fresh page after each deploy.
Now learn it: break and fix it yourself in 403 Forbidden after every deploy, then take Level 02 · Permissions and ownership. Open in the interactive reference · Link to this answer
Files and permissions
404 everywhere after a deploy: broken symlink
current: broken symbolic link to /srv/www/releases/20261029-2
What it means
The web root is a symbolic link, and the folder it points at no longer exists. file reports a "broken symbolic link": the link is there, its target is not, so nginx finds nothing and every page is 404.
Causes, most likely first
A cleanup job removed the release the link points at. The link survives its target and now points at nothing.
Check
readlink /srv/www/current # the target ls -l /srv/www/releases # that release is not in the list: this is your causeFix
Point it at a release that exists:
ln -sfn /srv/www/releases/NEW /srv/www/current, or atomicallyln -s NEW current.tmp && mv -T current.tmp current.The deploy wrote a relative target that resolves somewhere else. A relative target is read from the link's own folder, not from where the deploy ran.
Check
readlink /srv/www/current # does not start with /: relative find /srv/www -xtype l # every link whose target is goneFix
Recreate the link with an absolute target.
Prevent it
Never delete the release the link points at; keep the last few releases.
Now learn it: break and fix it yourself in Symlink broken after deploy, then take Level 03 · Links, archives and text tools. Open in the interactive reference · Link to this answer
Files and permissions
command not found (but it works for me)
/bin/sh: 1: backup-uploads.sh: not found
What it means
The shell looked for the command in each folder of its PATH and did not find it. /bin/sh: 1: means dash (Ubuntu's sh) ran it, as cron and many scripts do, not your interactive bash. The same name works for you because your shell has a different PATH, or the file is somewhere only you look.
Causes, most likely first
A different PATH. cron uses /usr/bin:/bin; sudo uses secure_path, which on Rocky/RHEL leaves out /usr/local/bin. A tool in /usr/local/bin or your home is found by you, not by them.
Check
command -v backup-uploads.sh # where your shell finds it env -i PATH=/usr/bin:/bin /bin/sh -c 'backup-uploads.sh' # not found here too: this is your cause sudo grep secure_path /etc/sudoers # the PATH sudo usesFix
Use absolute paths in the job, or set
PATH=at the top of the crontab.The script exists but its
#!interpreter does not. dash reports that as "not found" too, which hides the real problem.Check
head -1 "$(command -v backup-uploads.sh)" # an interpreter that is not installedFix
Install the interpreter or correct the shebang.
The package is not installed on this machine.
Check
command -v backup-uploads.sh # no output in your shell eitherFix
sudo apt install PACKAGE(Ubuntu suggests which); on Rocky,dnf provides '*/NAME'finds it.
Prevent it
Scripts for automation use absolute paths or set PATH themselves.
Now learn it: break and fix it yourself in Cron job that never works, then take Level 08 · Scheduling with cron. Open in the interactive reference · Link to this answer
Files and permissions
Argument list too long
-bash: /usr/bin/rm: Argument list too long
What it means
The shell expanded * into every file name in the folder and tried to pass them all to rm. The kernel limits how much a single command line may hold (getconf ARG_MAX), and this list was larger, so rm never started.
Cause
The glob expands to more arguments than the kernel accepts in one command line. It happens only in folders with a huge number of files.
Check
ls /var/lib/php/sessions | wc -l # hundreds of thousands: this is your cause getconf ARG_MAX # the limit in bytesFix
Let find do it without a glob:
find /var/lib/php/sessions -type f -mmin +1440 -delete, orfind DIR -type f -print0 | xargs -0 rm.
Prevent it
Clean up with a scheduled find -delete; do not let one folder collect millions of files.
Now learn it: break and fix it yourself in No space left, with space left, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Processes
Processes
High load average, CPU at 100%
load average: 2.02, 1.88, 1.53
What it means
The load average is the number of processes running or waiting to run, averaged over 1, 5 and 15 minutes. Compare it with the number of CPUs (nproc): load above that means work is queueing. On Linux it also counts processes waiting on disk, so high load is not always CPU.
Causes, most likely first
A runaway job or loop uses a whole CPU. One process near 100% in top is the sign.
Check
top # press P: one process at the top near 100% ps aux --sort=-%cpu | headFix
kill PID(SIGTERM) for a stray job, or limit it:sudo systemctl set-property NAME CPUQuota=50%.Too many workers for the CPUs. Many processes share the CPUs, each modest, but together more than the box has.
Check
uptime && nproc # load well above the CPU count vmstat 1 5 # us+sy near 100 and a long r columnFix
Lower the worker count to fit the CPUs, or add CPUs.
Processes waiting on disk, not CPU. Linux counts them in the load too.
Check
vmstat 1 5 # wa and b high, us low: see I/O waitFix
Treat it as disk (see High load, idle CPU).
On a cloud VM, CPU steal or used-up burst credits. The hypervisor gives you less CPU than the VM thinks it has.
Check
vmstat 1 5 # st high: the hypervisor takes the CPUFix
Move to a larger or non-burstable instance type.
Prevent it
Run batch work under limits (systemd-run -p CPUQuota=) or off-peak.
Now learn it: break and fix it yourself in A process eating the CPU, then take Level 05 · Processes and signals. Open in the interactive reference · Link to this answer
Processes
Half-written file or stale lock after kill -9
export.csv.part left behind, batchd.lock still present
What it means
The process was killed with SIGKILL (kill -9). SIGKILL cannot be caught: the program gets no chance to flush buffers, rename its finished file or remove its lock. What it left behind is a half-written file and a lock that now blocks the next start.
Cause
SIGKILL cannot be caught, so no flush, no rename, no cleanup happened. The
.partfile and the lock are leftovers.Check
ls -l /var/lib/batch # .part and .lock files left behind cat /var/lib/batch/batchd.lock && ps -p $(cat /var/lib/batch/batchd.lock) # no process: the lock is staleFix
Remove the stale lock only after checking no process owns it, and rerun the job for a complete file. Next time:
kill PID(TERM), wait, and use -9 only if it ignores TERM.
Prevent it
Stop services with systemctl stop, which sends TERM and waits.
Now learn it: break and fix it yourself in kill -9 or a clean stop, then take Level 05 · Processes and signals. Open in the interactive reference · Link to this answer
Processes
Zombie <defunct> processes
[convert] <defunct>
What it means
A zombie is a process that has already exited, and whose exit status its parent has not collected yet (with wait()). It uses no CPU or memory, only a slot in the process table, and kill -9 cannot remove it because it is already dead.
Causes, most likely first
The parent never called wait() for its exited children. Until it does, each child stays as a zombie.
Check
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/' # the zombies and their parent (PPID) ps -fp PPID # the parent that does not reapFix
Restart or stop the parent: init then adopts and reaps the zombies. Fix the program to wait() (or ignore SIGCHLD).
In a container, PID 1 is your program. It does not reap orphaned children the way init does, so they pile up.
Check
ps -p 1 -o comm= # your program, not an initFix
docker run --init, or tini as PID 1.
Prevent it
A few zombies are harmless; thousands exhaust PIDs. Alert on the count.
Now learn it: break and fix it yourself in Zombies that will not die, then take Level 05 · Processes and signals. Open in the interactive reference · Link to this answer
Processes
Already running (stale PID file)
reportd: another instance is running (pid 1187), exiting
What it means
The daemon found its PID file, read a process number from it, saw that a process with that number exists, and refused to start a second copy. After a crash or reboot that number usually belongs to some other program.
Causes, most likely first
The PID file survived a crash or reboot, and its number now belongs to another process.
Check
cat /run/reportd.pid ps -fp 1187 # another program: the file is staleFix
Remove the stale PID file, then start the service. Do not kill that PID: it is someone else's.
It really is running: a copy started by hand, outside systemd.
Check
pgrep -a reportd # a real reportd: a second copy is runningFix
Stop that copy, then start the service through systemctl.
Prevent it
Keep PID files in /run (cleared at boot) and let systemd track the main PID.
Now learn it: break and fix it yourself in Already running, but it is not, then take Level 05 · Processes and signals. Open in the interactive reference · Link to this answer
Processes
Killed, with no error in the log
Out of memory: Killed process 2759 (java) total-vm:5832104kB, anon-rss:3201552kB
What it means
The kernel killed the process because memory ran out. "Out of memory: Killed process 2759 (java)" names the victim; anon-rss is how much memory it really used. The program gets SIGKILL, so it writes nothing to its own log.
Causes, most likely first
The machine ran out of memory and the kernel's OOM killer chose this process, usually the biggest.
Check
sudo journalctl -k | grep -i -e 'out of memory' -e oom-kill # plain Out of memory: the whole box free -h # now, not at the timeFix
Size the heap or workers to the machine (e.g. -Xmx1g), add memory, or move a workload away.
A cgroup limit was hit (MemoryMax=, or a container's memory limit). The box has memory free, but this group may not use more.
Check
sudo journalctl -k | grep -i 'memory cgroup out of memory' # a line here: a limit systemctl show reports -p MemoryMax -p MemoryCurrentFix
Raise MemoryMax= only if the service really needs more; otherwise find what grew.
No OOM line at all: something else sent SIGKILL, such as a supervisor or a timeout.
Check
sudo journalctl -k | grep -ci oom # 0: not the OOM killerFix
See status=9/KILL.
Prevent it
Set MemoryMax= per service and alert on available memory, not on used.
Now learn it: break and fix it yourself in Killed by the OOM killer, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Services
Services
status=203/EXEC
orders-api.service: Failed to locate executable /usr/local/bin/orders-api: No such file or directory
What it means
systemd could not start the program in ExecStart=. 203/EXEC is systemd's code for "the exec step failed": the process was never started, so there is no log from the program, only from systemd. The journal line after it gives the reason.
Causes, most likely first
ExecStart points at a path that does not exist (a typo, or the binary was not installed).
Check
journalctl -u orders-api -n 10 # No such file or directory: this is your cause ls -l /usr/local/bin/orders-apiFix
Fix ExecStart (absolute path), then
sudo systemctl daemon-reload && sudo systemctl restart orders-api.The file is not executable, or is a script with CRLF in its shebang.
Check
ls -l /usr/local/bin/orders-api # no x file /usr/local/bin/orders-api # with CRLF line terminatorsFix
chmod 755the file, or convert the line endings.A bare command name that is not in systemd's fixed search path. systemd does not use your shell's PATH.
Check
systemctl cat orders-api | grep ExecStart # a name without /Fix
Write the absolute path in ExecStart.
On Rocky/RHEL, SELinux blocks a binary with the wrong label, usually one moved from a home folder.
Check
journalctl -u orders-api -n 10 # Permission denied ls -Z /usr/local/bin/orders-api # user_home_t: moved from a home folderFix
sudo restorecon -v /usr/local/bin/orders-api.
Prevent it
Install binaries with the package that ships the unit; check with systemd-analyze verify.
Now learn it: break and fix it yourself in status=203/EXEC, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Unit is masked
Failed to start nginx.service: Unit nginx.service is masked.
What it means
Masking links a unit to /dev/null so that nothing can start it, not even by hand or as a dependency. Someone did that on purpose, often during maintenance, and systemd refuses every start.
Cause
Someone ran
systemctl mask, linking the unit to /dev/null.Check
systemctl is-enabled nginx # masked ls -l /etc/systemd/system/nginx.service # -> /dev/nullFix
Ask why it was masked, then
sudo systemctl unmask nginx && sudo systemctl enable --now nginx.
Prevent it
Prefer disable for maintenance; leave a note when you mask.
Now learn it: break and fix it yourself in Unit is masked, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Unit file changed on disk
Warning: The unit file, source configuration file or drop-ins of api.service changed on disk. Run 'systemctl daemon-reload' to reload units.
What it means
systemd keeps its own copy of each unit file, read at the last daemon-reload. You edited the file on disk, so systemd warns that its copy is older, and a restart still uses the old settings.
Cause
systemd works from the copy it loaded at the last daemon-reload, not from the file on disk.
Check
systemctl show api -p NeedDaemonReload # yes: the files changed since systemd loaded them systemctl cat api # the files on diskFix
sudo systemctl daemon-reload && sudo systemctl restart api.
Prevent it
Use systemctl edit (it reloads for you), or always daemon-reload after editing.
Now learn it: break and fix it yourself in The unit change did not take · status=203/EXEC, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Service missing after every reboot
Loaded: loaded (/etc/systemd/system/metrics-agent.service; disabled; preset: enabled)
What it means
disabled in the Loaded line means nothing starts this unit at boot. preset: enabled is only the distribution's suggestion, not the current state. A service you started by hand runs until the next reboot.
Causes, most likely first
It was started but never enabled. On Rocky/RHEL packages install services disabled; Ubuntu usually enables them, so habits from one break on the other.
Check
systemctl is-enabled metrics-agent # disabled: this is your causeFix
sudo systemctl enable --now metrics-agent.The unit has no [Install] section, so enable has nothing to link.
Check
systemctl is-enabled metrics-agent # static systemctl show -p WantedBy metrics-agent # empty: nothing starts it at bootFix
Add
[Install]withWantedBy=multi-user.target, daemon-reload, enable.It is enabled, but its dependency fails at boot, so it is skipped or fails too.
Check
journalctl -b -u metrics-agent # it tried and failed, or a dependency failedFix
Fix the dependency the journal names.
Prevent it
Reboot new servers once before production to prove they come back.
Now learn it: break and fix it yourself in Gone after every reboot · Fails only after a reboot, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Failed to restart: Access denied
Failed to restart ssh.service: Access denied
What it means
systemctl asked systemd to restart a system service and systemd refused because your user may not manage units. systemd checks that through polkit; with no way to ask for a password it answers "Access denied".
Causes, most likely first
Managing system services needs root, or a polkit rule that allows your user.
Check
id # not root sudo -l # whether sudo allows itFix
sudo systemctl restart ssh(sshd on Rocky). For CI, a narrow sudoers rule for that exact command.Over ssh or in a script there is no polkit agent to ask for a password, so it says Access denied instead of prompting.
Check
tty # not a tty: nothing could promptFix
Use sudo, or a NOPASSWD rule for that exact command.
Prevent it
Grant exact commands in sudoers, not ALL.
Now learn it: break and fix it yourself in Sorry, user deploy is not allowed to execute, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Start request repeated too quickly
billing.service: Start request repeated too quickly.
What it means
The service crashed and systemd restarted it, again and again. After too many starts in a short time (StartLimitBurst= within StartLimitIntervalSec=, 5 in 10 s by default) systemd stops trying and refuses even manual starts. The crash is the real problem; this message only says systemd gave up.
Cause
The service crashed more than StartLimitBurst times within StartLimitIntervalSec.
Check
systemctl status billing # Result: start-limit-hit journalctl -u billing -n 50 # the first error, before the restarts, is the real oneFix
Fix the cause, then
sudo systemctl reset-failed billing && sudo systemctl start billing.
Prevent it
Validate config before deploying it; use RestartSec= so retries are spaced out.
Now learn it: break and fix it yourself in Start request repeated too quickly, then take Level 07 · Logs and failing services. Open in the interactive reference · Link to this answer
Services
Address already in use
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
What it means
nginx tried to bind (claim) port 80 on every address (0.0.0.0) and the kernel said another socket already holds it. Only one program may listen on an address and port, so nginx cannot start.
Causes, most likely first
Another service owns the port, such as Apache or an old instance.
Check
sudo ss -tlnp 'sport = :80' # users:(("apache2"...)) or httpd: this is your causeFix
sudo systemctl disable --now apache2(httpd on Rocky), or move one service to another port.A second copy of the same service is already running.
Check
sudo ss -tlnp 'sport = :80' # nginx itself owns it pgrep -a nginx # more than one masterFix
Stop the extra copy, then manage it only through systemctl.
A container publishes the port.
Check
sudo ss -tlnp 'sport = :80' # docker-proxyFix
Change that container's
-pmapping.A systemd .socket unit holds it for socket activation.
Check
sudo ss -tlnp 'sport = :80' # systemd systemctl list-sockets | grep :80Fix
sudo systemctl disable --now NAME.socket.
Prevent it
Watch what package installs pull in, and pin ports per service.
Now learn it: break and fix it yourself in Address already in use, then take Level 07 · Logs and failing services. Open in the interactive reference · Link to this answer
Services
Job failed because the control process exited with error code
Job for nginx.service failed because the control process exited with error code.
What it means
systemctl's own message: the start command failed, but it does not say why. The "control process" is the start step (for nginx, the config test and the daemon starting up). The reason is in the journal.
Causes, most likely first
The config is invalid. nginx tests it before starting and exits with an error.
Check
sudo nginx -t # an error with a file and line number: this is your causeFix
Fix the line it names, then start again.
Something the daemon needs fails: the port is in use, a file is missing, or a permission.
Check
journalctl -xeu nginx.service # the first error line is the causeFix
Fix what the journal names (see Address already in use for ports).
On Rocky/RHEL, an SELinux denial stops it.
Check
sudo ausearch -m avc -ts recent # a denial for nginxFix
Fix the label, port type or boolean (see the SELinux entries).
Prevent it
Test configs (nginx -t, apachectl configtest) before reload.
Now learn it: break and fix it yourself in Address already in use, then take Level 07 · Logs and failing services. Open in the interactive reference · Link to this answer
Services
Connection refused only after a reboot
Error: connect ECONNREFUSED 127.0.0.1:5432
What it means
ECONNREFUSED means nothing was listening on 127.0.0.1:5432 when the app tried to connect. It happens only after a reboot: at boot the app started before PostgreSQL was ready, while by hand PostgreSQL is already running.
Causes, most likely first
It starts before the service it needs: there is no After= ordering, so systemd starts both at once.
Check
systemctl cat inventory | grep -E 'After|Wants|Requires' # no postgresql: this is your cause journalctl -b -u inventory -u postgresql # inventory failed before postgresql was upFix
A drop-in with
[Unit] After=postgresql.service Wants=postgresql.service; daemon-reload; reboot to test.The dependency has started but does not accept connections yet, or runs on another host: After= cannot help.
Check
journalctl -b -u inventory -u postgresql # inventory failed after postgresql startedFix
Make the app retry its first connection with backoff.
Prevent it
Declare every local dependency with After= plus Wants= or Requires=.
Now learn it: break and fix it yourself in Fails only after a reboot, then take Level 07 · Logs and failing services. Open in the interactive reference · Link to this answer
Services
The unit files have no installation config
The unit files have no installation config (WantedBy=, RequiredBy=, UpheldBy=,
What it means
systemctl enable creates links from a target (such as multi-user.target) to the unit, using the unit's [Install] section. This unit has none, so there is nothing to enable.
Causes, most likely first
The unit has no [Install] section with WantedBy=.
Check
systemctl cat NAME # no [Install] sectionFix
Add
[Install]withWantedBy=multi-user.target, daemon-reload, enable.It is meant to be started by something else, such as a .timer or a .socket.
Check
systemctl list-timers --all | grep NAME # a timer runs itFix
Enable the timer instead:
sudo systemctl enable --now NAME.timer.
Prevent it
Start unit files from a template that includes [Install].
Now learn it: break and fix it yourself in Gone after every reboot, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Unit not found
Failed to restart mysql.service: Unit mysql.service not found.
What it means
systemd has no unit file with that name loaded. Either it does not exist on this machine, it has another name here, or systemd has not reloaded since it was added.
Causes, most likely first
The package is not installed, or the service has another name here (mysql on Ubuntu, mysqld or mariadb on Rocky; apache2 or httpd).
Check
systemctl list-unit-files | grep -i -e mysql -e maria # the real name, or nothingFix
Use the real name from list-unit-files, or install the package that provides the service.
A unit file was added or renamed without
systemctl daemon-reload.Check
ls /etc/systemd/system /usr/lib/systemd/system | grep -i sql # the file is thereFix
sudo systemctl daemon-reload.A typo, or a user service that needs
systemctl --user.Check
systemctl --user list-unit-files | grep -i NAMEFix
Correct the name, or use
systemctl --user.
Prevent it
Check systemctl list-unit-files before you write a unit name into a script or runbook.
Now learn it: break and fix it yourself in The unit change did not take, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Unit has a bad unit file setting
Failed to start worker.service: Unit worker.service has a bad unit file setting.
What it means
systemd read the unit file and found a line it cannot use, so it refuses to start the unit. The journal says which line.
Causes, most likely first
A required line is missing, such as ExecStart= (the journal says: Service has no ExecStart=...).
Check
journalctl -b -u worker | tail # Service has no ExecStart=Fix
Add the line, then
sudo systemctl daemon-reload && sudo systemctl start worker.A typo in a key or a section name, or a value systemd cannot parse.
Check
systemd-analyze verify /etc/systemd/system/worker.service # names the file and line systemctl cat workerFix
Fix the line it names, daemon-reload, start.
Prevent it
Run systemd-analyze verify on every unit file before you install it.
Now learn it: break and fix it yourself in status=203/EXEC · The unit change did not take, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Exec format error
-bash: ./node_exporter: cannot execute binary file: Exec format error
What it means
The kernel was asked to run a file and did not recognise it as a program it can run. "Exec format error" (ENOEXEC) means the file is not a binary for this CPU, and not a script with a #! line.
Causes, most likely first
The binary is built for another CPU: an arm64 build on x86_64, or the other way round.
Check
uname -m # x86_64 or aarch64 file ./node_exporter # ELF ... ARM aarch64 on an x86_64 box: this is your causeFix
Download the build for your architecture (amd64 for x86_64, arm64 for aarch64).
A script without a
#!first line, started by systemd or exec. Without it the kernel does not know what runs it.Check
head -1 SCRIPT # must start with #!Fix
Add a shebang such as
#!/bin/bashas the first line.The download is an archive or an HTML error page, not the program.
Check
file ./node_exporter # gzip compressed data or HTML documentFix
Unpack the archive, or download again from the right URL.
Prevent it
Pick downloads by uname -m, and give every script a #! line.
Now learn it: break and fix it yourself in status=203/EXEC, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
System has not been booted with systemd
System has not been booted with systemd as init system (PID 1). Can't operate.
What it means
systemctl talks to systemd running as PID 1, the first process. Here PID 1 is something else, so there is no systemd to talk to.
Causes, most likely first
In a container, PID 1 is your program. Docker and most containers do not run systemd.
Check
ps -p 1 -o comm= # bash, node or your app, not systemdFix
Run the program in the foreground as the container's command, not with systemctl.
WSL started without systemd.
Check
ps -p 1 -o comm= # init, not systemdFix
Add
[boot]andsystemd=trueto /etc/wsl.conf, runwsl --shutdownin Windows, then reopen it.
Prevent it
Practise services on a VM or a cloud instance, where systemd is PID 1; keep a container to one foreground process.
Now learn it: break and fix it yourself in Gone after every reboot, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Services
Cron ignores a file in /etc/cron.d
(*system*db-backup) ERROR (Syntax error, this crontab file will be ignored)
What it means
cron read a file in /etc/cron.d, could not parse a line, and ignored the whole file. *system*db-backup is cron's name for the system file /etc/cron.d/db-backup. None of its jobs run until it is fixed.
Causes, most likely first
/etc/cron.d lines need a user field after the five time fields. Without it, cron takes the command's first word as the user name.
Check
cat /etc/cron.d/db-backup # five fields then the command, no user: this is your cause journalctl -u cron -n 20 # bad username (crond on Rocky, or /var/log/cron)Fix
Add the user:
*/10 * * * * postgres pg_dump ....Wrong owner or a writable mode. cron refuses files not owned by root or writable by others.
Check
ls -l /etc/cron.d # owned by root, not group or world writableFix
sudo chown root:root FILE && sudo chmod 644 FILE.On Ubuntu and Debian, a dot in the file name. cron skips the file without a word, so its jobs never run.
Check
ls /etc/cron.d # db-backup.cron or similarFix
Rename it with letters, digits, - and _ only.
Prevent it
Name cron.d files with letters, digits, - and _ only, and run each job as the user that owns the work.
Now learn it: break and fix it yourself in Cron job as the wrong user, then take Level 08 · Scheduling with cron. Open in the interactive reference · Link to this answer
Services
new crontab file is missing newline before EOF
new crontab file is missing newline before EOF, can't install.
What it means
crontab FILE checks the file before installing it and refuses one whose last line does not end with a newline, because cron would drop that last line.
Cause
The last line has no newline (printf without \n is the usual source).
Check
tail -c1 file | od -c # the last character is not \nFix
echo >> file, thencrontab file.
Prevent it
Use echo or a here-document when generating crontabs.
Now learn it: break and fix it yourself in Cron job that never works, then take Level 08 · Scheduling with cron. Open in the interactive reference · Link to this answer
Services
pg_dump: role "root" does not exist
pg_dump: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
What it means
PostgreSQL accepted the connection on the local socket, then looked for a database role named "root" and found none. With no -U, the client uses your Linux user name as the role name.
Causes, most likely first
No -U given: the client uses the Linux user name as the role (root here), and no such role exists.
Check
sudo -u postgres psql -c '\du' # the roles that exist; root is not among themFix
Run the job as postgres:
sudo -u postgres pg_dump ..., or user postgres in cron.d. Better: give the job its own role and pass -U.PGUSER is set to a role that does not exist.
Check
printenv PGUSER PGHOST PGPORT # what the job inheritsFix
Unset or correct PGUSER.
It reached another cluster or port where that role was never created.
Check
pg_lsclusters # Ubuntu: which cluster listens on which portFix
Pass the right -p (or -h) for the cluster. Do not create a superuser role named root to silence it.
Prevent it
Give automation its own role and Linux user.
Now learn it: break and fix it yourself in Cron job as the wrong user, then take Level 08 · Scheduling with cron. Open in the interactive reference · Link to this answer
Services
Variable set in my shell, missing in the service
Error: DATABASE_URL is not set
What it means
The program started without a variable it needs. Under systemd a service gets only the environment its unit gives it: nothing from your login shell.
Causes, most likely first
Services do not read ~/.bashrc, ~/.profile, your exports or /etc/environment.
Check
sudo cat /proc/$(pgrep -o reports)/environ | tr '\0' '\n' | cut -d= -f1 # the names the running process has, without valuesFix
A drop-in with
EnvironmentFile=/etc/app/app.env(mode 600), then daemon-reload and restart. Keep secrets out ofEnvironment=in the unit: any user can read it with systemctl show.The EnvironmentFile= path is wrong. With a leading - systemd skips a missing file silently.
Check
systemctl show reports-api -p EnvironmentFiles # the files it loads; ignore_errors=yes means a missing one is skipped ls -l /etc/app/app.envFix
Fix the path, daemon-reload and restart.
The variable is set for a different user than the service runs as.
Check
systemctl show -p User reports-apiFix
Set it in the unit or its EnvironmentFile, not in a user's profile.
Prevent it
Keep a service's configuration in its unit or an EnvironmentFile under /etc, never in a login shell.
Now learn it: break and fix it yourself in Works in my shell, not as a service, then take Level 06 · systemd services. Open in the interactive reference · Link to this answer
Disks
Disks
No space left on device
touch: cannot touch '/tmp/x': No space left on device
What it means
The kernel could not write because the file system had nothing left to give: no free blocks, or no free inodes (the slots that hold one file each). ENOSPC is the code; the path tells you which file system to check.
Causes, most likely first
The file system is full.
Check
df -h /tmp # Use% 100 on the file system that holds the path sudo du -xh --max-depth=1 / 2>/dev/null | sort -h | tail # the biggest foldersFix
Delete or compress what you do not need; truncate a runaway log (
truncate -s 0) rather than rm it.Inodes are exhausted: space is left, but no new file can be created.
Check
df -i /tmp # IUse% 100: inodes, not spaceFix
Remove the small files (see the inodes entry).
Deleted files are still held open. The space returns only when the process closes them.
Check
sudo lsof +L1 # (deleted) files still taking spaceFix
Restart the process that holds them.
Only root's reserve is left (5% on ext4 by default), so normal users fail first.
Check
df -h / # Avail 0 while Use% shows about 95%Fix
Free space as above. Lowering the reserve (
tune2fs -m) buys minutes, not a fix.
Prevent it
Alert at 80%, rotate logs by size, keep data on its own volume.
Now learn it: break and fix it yourself in Disk full, but du finds nothing · A debug log filling the disk · No space left, with space left, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
df says full, du finds much less
/dev/nvme0n1p1 20G 20G 0 100% /
What it means
df asks the file system how much is used; du adds up the files it can see. When df says much more, the space is used by something du cannot see.
Causes, most likely first
A deleted file is still open by a process. It has no name, so du misses it, but its space stays used.
Check
sudo lsof +L1 # (deleted) files and the process holding themFix
sudo systemctl restart SERVICE, orsudo truncate -s 0 /proc/PID/fd/N.Files are hidden under a mount point: they were written before the disk was mounted over that folder.
Check
sudo mkdir -p /mnt/rootfs && sudo mount -o bind,ro / /mnt/rootfs && sudo du -sh /mnt/rootfs/data # space under the /data mount point; umount /mnt/rootfs afterFix
Stop the writer, unmount, move the files, mount again.
du ran without sudo and skipped folders it could not read.
Check
sudo du -xsh / # compare with dfFix
Run du with sudo.
Prevent it
Use logrotate copytruncate (or a reopen signal); never rm a log a process writes.
Now learn it: break and fix it yourself in Disk full, but du finds nothing · A debug log filling the disk, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
No space left, with space left (inodes)
/dev/nvme0n1p1 1310720 1310720 0 100% /
What it means
Every file needs an inode, and this file system has none left: IUse% is 100%. Space is free, but no new file, not even an empty one, can be created, so it reads as "No space left on device".
Causes, most likely first
Millions of tiny files: sessions, cache, mail queues.
Check
df -i # IUse% 100 sudo du --inodes -x / 2>/dev/null | sort -n | tail # the folders with the most filesFix
sudo find DIR -type f -mmin +1440 -deletefor the folder that grew.Mostly on ext4, which fixes the inode count when the file system is made. XFS (Rocky's default) allocates inodes as needed, so this is rare there.
Check
df -T / # ext4Fix
Clean up as above; for a volume that will always hold many small files, make it with more inodes (
mkfs.ext4 -i).
Prevent it
Schedule cleanup of session and cache folders; alert on inode use.
Now learn it: break and fix it yourself in No space left, with space left, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
Read-only file system
touch: cannot touch '/data/x': Read-only file system
What it means
The kernel refused the write because the file system is mounted read-only (EROFS). Root cannot override that. The question is who made it read-only and why.
Causes, most likely first
ext4 found an error and remounted itself read-only (errors=remount-ro) to protect your data.
Check
sudo dmesg -T | grep -i -e ext4 -e 'read-only' # Remounting filesystem read-only: this is your causeFix
Stop writers, snapshot the volume if you can, umount, run fsck on the device, mount again. Do not force rw on a damaged file system.
The disk went away or returned I/O errors, such as a detached cloud volume.
Check
sudo dmesg -T | grep -i -e 'I/O error' -e xfs # I/O errors or an XFS shutdownFix
Fix the disk or attachment; for XFS run
xfs_repairon the unmounted device.The root file system in emergency mode, or mounted ro in fstab.
Check
findmnt -no OPTIONS -T /data # ro here: the mount itself is read-onlyFix
In emergency mode:
mount -o remount,rw /; otherwise fix the fstab options.Read-only for one service only: ProtectSystem=strict or ReadOnlyPaths= in its unit.
Check
systemctl show SERVICE -p ProtectSystem -p ReadWritePaths # strict, and the path is not listedFix
Allow the path with
ReadWritePaths=in a drop-in.
Prevent it
Watch dmesg and disk health; keep backups. Do not force rw on a damaged file system.
Now learn it: break and fix it yourself in Read-only file system · Emergency mode after an fstab change, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Disks
umount: target is busy
umount: /data: target is busy.
What it means
umount refuses while anything still uses the file system: an open file, a process's working directory, or another mount on top of it.
Causes, most likely first
A process has a file open or its working directory there (your own shell counts).
Check
sudo fuser -vm /data # the processes using it sudo lsof +D /dataFix
Stop the service, cd out, then umount.
Something else uses it: a mount inside it, a swap file or a loop device.
Check
findmnt -R /data; swapon --show; losetup -a # mounts, swap and loop devices on itFix
Unmount inner mounts or swapoff first. Avoid
umount -lunless you know what holds it: the writes carry on unseen.
Prevent it
RequiresMountsFor= in units makes the order explicit.
Now learn it: break and fix it yourself in Read-only file system, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Disks
e2fsck: Cannot continue, aborting
/dev/nvme1n1p1 is mounted.
e2fsck: Cannot continue, aborting.
What it means
e2fsck refuses to check a mounted file system, because changing it while the kernel also writes to it would corrupt it.
Cause
The file system is mounted.
Check
findmnt /dev/nvme1n1p1 # a TARGET: it is mountedFix
Unmount it first; for / use a rescue boot or a check at boot.
Prevent it
Keep data on separate volumes you can unmount.
Now learn it: break and fix it yourself in Read-only file system, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Disks
resize2fs: Nothing to do!
The filesystem is already 5214459 (4k) blocks long. Nothing to do!
What it means
resize2fs grows a file system to fill its partition. It found the file system already as big as the partition, so there is nothing to grow: the space you added is in a layer below.
Causes, most likely first
The partition was not grown; the file system already fills it.
Check
lsblk # disk bigger than the partition: this is your causeFix
sudo growpart /dev/nvme0n1 1 && sudo resize2fs /dev/nvme0n1p1(xfs_growfs / for XFS; growpart is in cloud-guest-utils on Ubuntu, cloud-utils-growpart on Rocky).On LVM: the physical and logical volumes were not grown.
Check
sudo pvs; sudo lvs # PFree or VFree unusedFix
growpart, then
sudo pvresize /dev/nvme0n1p3 && sudo lvextend -r -l +100%FREE VG/LV.The kernel has not seen the bigger disk yet.
Check
lsblk # the disk still at the old sizeFix
Rescan it (for a SCSI disk,
echo 1 | sudo tee /sys/class/block/sdb/device/rescan) or reboot.
Prevent it
Script the three steps: volume, partition, file system.
Now learn it: break and fix it yourself in The disk grew, the filesystem did not, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Disks
You are in emergency mode
Dependency failed for local-fs.target - Local File Systems.
What it means
systemd could not mount a file system listed in /etc/fstab, so local-fs.target failed and it stopped at an emergency shell rather than boot with data missing.
Causes, most likely first
An fstab line for a disk that is missing or has a wrong UUID, without nofail.
Check
journalctl -xb | grep -i -e failed -e 'timed out' # Timed out waiting for device: this is your cause blkid # compare the UUIDs with /etc/fstab cat /etc/fstabFix
mount -o remount,rw /, fix fstab,systemctl daemon-reload,mount -a, thensystemctl default.A file system that fails its check.
Check
journalctl -xb | grep -i fsck # errors from the checkFix
Run fsck (ext4) or xfs_repair (XFS) on that unmounted device, then
systemctl default.
Prevent it
Run mount -a after every fstab change; use nofail for non-critical disks.
Now learn it: break and fix it yourself in Emergency mode after an fstab change, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Disks
mount: can't find UUID
mount: /data: can't find UUID=7c1e0b6a-90d1-4b8e-a3f5-2e64c2a71b9f.
What it means
fstab names the disk by UUID, and no attached block device has that UUID, so mount does not know which disk you mean.
Causes, most likely first
A typo in the UUID, or the disk was replaced.
Check
sudo blkid # the real UUIDs lsblk -fFix
Copy the UUID from blkid into /etc/fstab, then
sudo mount -a.The disk was formatted again (mkfs gives it a new UUID) or is not attached.
Check
lsblk -f # the disk is missing, or has another UUIDFix
Attach it, or update fstab with the new UUID.
Prevent it
Paste UUIDs, never type them.
Now learn it: break and fix it yourself in Emergency mode after an fstab change, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Disks
mount: wrong fs type, bad option, bad superblock
mount: /mnt/data: wrong fs type, bad option, bad superblock on /dev/sdc, missing codepage or helper program, or other error.
What it means
mount could not make sense of what is on the device with the type and options given. The message lists every possible reason because the kernel only reports a generic failure; dmesg usually has the specific one.
Causes, most likely first
The device has no file system yet (a new volume).
Check
lsblk -f # FSTYPE empty sudo blkid /dev/sdc # no outputFix
Only for a new, empty volume:
sudo mkfs.ext4 /dev/sdc(this erases it).You mounted the whole disk (/dev/sdc) and the file system is on a partition (/dev/sdc1).
Check
lsblk -f # the FSTYPE is on sdc1Fix
Mount the partition and type that lsblk -f shows.
The helper is missing: nfs-common (nfs-utils on Rocky) for NFS, cifs-utils for SMB.
Check
ls /sbin/mount.nfs /sbin/mount.cifs # missingFix
sudo apt install nfs-commonor cifs-utils (dnf install nfs-utilson Rocky).A misspelled mount option.
Check
sudo dmesg | tail # unknown parameter or bad optionFix
Fix the option.
Prevent it
Check lsblk -f before mount or mkfs, and test every fstab line with sudo mount -a.
Now learn it: break and fix it yourself in Emergency mode after an fstab change · The disk grew, the filesystem did not, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Disks
logrotate: parent directory has insecure permissions
error: skipping "/var/log/orders/orders.log" because parent directory has insecure permissions (It's world writable or writable by group which is not "root") Set "su" directive in config file to tell logrotate which user/group should be used for rotation.
What it means
logrotate refuses to rotate logs in a folder that someone other than root can write to, because a user could swap files and trick root into overwriting something else. It skips the file, so the log grows forever.
Cause
The log folder is writable by a non-root group or by everyone.
Check
ls -ld /var/log/orders # w for group or others sudo logrotate -d /etc/logrotate.d/orders # the same message in the dry runFix
Add
su orders ordersto the rule, orchmod 755the folder; thensudo logrotate -fto test.
Prevent it
Run logrotate -d after every new rule.
Now learn it: break and fix it yourself in logrotate is not rotating, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
Space not freed after log rotation
orders 1204 orders 3w REG 8,1 12025908019 0 131003 /var/log/orders/orders.log.1 (deleted)
What it means
logrotate renamed the log and later deleted it, but the program still has the old file open and keeps writing there. (deleted) in lsof means the space is still in use until the program closes the file.
Causes, most likely first
The rule renames the file (create) while the program keeps it open; compress then deletes it.
Check
sudo lsof +L1 # .log.1 (deleted) held by the programFix
Restart the program once to release the space.
No copytruncate and no postrotate reload, so the program is never told to reopen.
Check
grep -E 'copytruncate|postrotate' /etc/logrotate.d/*Fix
Add postrotate with the program's reload command, or copytruncate (it can lose lines written during the copy).
Prevent it
For programs that cannot reopen logs, use copytruncate; better, log to the journal.
Now learn it: break and fix it yourself in logrotate is not rotating, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
The journal is using gigabytes
Archived and active journals take up 9.2G in the file system.
What it means
systemd's journal stores logs under /var/log/journal. By default journald keeps it to 10% of the file system, capped at 4G, so a larger figure means a setting or leftover files.
Causes, most likely first
SystemMaxUse= was raised somewhere.
Check
systemd-analyze cat-config systemd/journald.conf | grep -i -e maxuse -e keepfree # the settings in effect, drop-ins includedFix
sudo journalctl --vacuum-size=500M, andSystemMaxUse=500Min a drop-in under /etc/systemd/journald.conf.d/, thensudo systemctl restart systemd-journald.Journal folders from another machine ID, such as an image cloned without a new /etc/machine-id, that journald does not clean.
Check
ls /var/log/journal; cat /etc/machine-id # folders that are not this machine's IDFix
Remove those folders once you no longer need their logs.
Prevent it
Cap the journal on every server image; ship logs off the box.
Now learn it: break and fix it yourself in The journal is eating the disk, then take Level 09 · Disk space. Open in the interactive reference · Link to this answer
Disks
Stale file handle
ls: cannot access '/mnt/shared': Stale file handle
What it means
An NFS client refers to files by handles the server gave it. The server no longer recognises them, because the export was restored, moved or recreated, so every access fails.
Cause
The export was restored, moved or recreated; the client's handles point at nothing.
Check
findmnt -t nfs4 df -h 2>&1 | grep -i stale # the stale mountFix
sudo umount -l /mnt/shared && sudo mount /mnt/shared.
Prevent it
Coordinate NFS server changes with the clients; remount after restores.
Now learn it: break and fix it yourself in Stale file handle, then take Level 10 · Mounts and file systems. Open in the interactive reference · Link to this answer
Networking
Networking
Temporary failure in name resolution
curl: (6) Could not resolve host: api.payments.example
What it means
The program asked the system resolver for the IP address of a name and got none. Name or service not known means a DNS server answered that the name does not exist; Temporary failure means no server answered. curl's (6) does not say which, so check.
Causes, most likely first
The resolver answered that the name does not exist (NXDOMAIN): a typo, a missing search domain, or a private zone this resolver cannot see.
Check
dig api.payments.example # status: NXDOMAIN: no such name there dig @10.0.0.2 api.payments.example # the server you expect answers it: the wrong resolver is in useFix
Fix the name or search domain, or use the resolver that serves that zone.
No answer at all: a wrong or unreachable nameserver, or systemd-resolved down.
Check
resolvectl status # Ubuntu: the real servers behind 127.0.0.53 dig api.payments.example # timed out: no server answersFix
Ubuntu: set nameservers in netplan, then
sudo netplan apply(/etc/resolv.conf is generated and edits are lost). Rocky:sudo nmcli connection modify NAME ipv4.dns 10.0.0.2 && sudo nmcli connection up NAME.No route or a firewall to the DNS server.
Check
dig @10.0.0.2 api.payments.example # timed out, while other traffic worksFix
Open UDP and TCP 53 to the resolver, or fix the route.
Prevent it
Manage DNS settings in one place (netplan, DHCP) and monitor resolution.
Now learn it: break and fix it yourself in Temporary failure in name resolution · Network is unreachable, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
dig shows the right address, the app uses another
Error: connect ETIMEDOUT 10.0.2.15:5432
What it means
dig asks a DNS server directly. Programs ask the system resolver, which reads /etc/hosts first and may use a cache, so they can get a different, older address and time out connecting to it.
Causes, most likely first
A stale line in /etc/hosts, which is read before DNS.
Check
getent hosts db.internal # what programs get dig +short db.internal # what DNS says grep db.internal /etc/hosts # the old address: this is your causeFix
Remove the stale /etc/hosts line.
A cache: systemd-resolved or nscd.
Check
getent hosts db.internal # old address, but not in /etc/hostsFix
sudo resolvectl flush-caches.The app resolved the name once at start (a connection pool, or the JVM's DNS cache).
Check
getent hosts db.internal # already right, yet the app still uses the old addressFix
Restart the app, and set a DNS TTL it honours.
Prevent it
Keep /etc/hosts minimal; use DNS with sensible TTLs.
Now learn it: break and fix it yourself in dig is right, the app is wrong, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
Network is unreachable
ping: connect: Network is unreachable
What it means
The kernel has no route to the destination, so it does not even try to send. That is different from a timeout: nothing left the machine.
Causes, most likely first
No default route.
Check
ip route # no default line ip route get 203.0.113.10 # Network is unreachableFix
sudo ip route add default via 10.0.1.1 dev eth0, and persist it in netplan (Ubuntu) or nmcli (Rocky).The interface is down, or got no address from DHCP.
Check
ip -br a # DOWN, or no IPv4 addressFix
Bring it up and fix DHCP or the static address.
The name resolves to IPv6 and there is no IPv6 route.
Check
ip -6 route # no default for IPv6Fix
Use -4 for now, or add the IPv6 route.
Prevent it
Change routes through netplan or DHCP, not by hand.
Now learn it: break and fix it yourself in Network is unreachable, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
Error: Nexthop has invalid gateway
Error: Nexthop has invalid gateway.
What it means
iproute2 refuses a route whose gateway is not on a network this machine is directly connected to, because it could not reach that gateway to hand it the packets.
Cause
The gateway is not on any directly connected subnet.
Check
ip -br a # your address and prefix ip route # the connected subnetsFix
Use a gateway inside your subnet (usually .1).
Prevent it
Check the subnet before adding routes.
Now learn it: break and fix it yourself in Network is unreachable, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
Connection timed out
curl: (28) Failed to connect to web-01 port 8080 after 134106 ms: Couldn't connect to server
What it means
The client sent a connection request (a SYN) and never got any answer, so after retrying it gave up. Silence usually means something dropped the packets on the way: a firewall or a wrong route. A refusal, by contrast, would come back at once.
Causes, most likely first
A firewall drops the packets: ufw or firewalld on the server, a cloud security group or network ACL on the way.
Check
sudo tcpdump -ni any tcp port 8080 # on the server while you retry: no SYN: dropped on the way; SYN but no reply: the host firewall sudo ufw status verbose # Ubuntu; sudo firewall-cmd --list-all on RockyFix
Host firewall:
sudo ufw allow from 10.0.1.0/24 to any port 8080 proto tcp. Security group: allow the port from the client's subnet only, not 0.0.0.0/0.The address is wrong or the host is down.
Check
getent hosts web-01 # the address the client uses curl -v localhost:8080 # on the server: works locally, so the service is upFix
Use the right address, or bring the host up.
Replies take another route back.
Check
sudo tcpdump -ni any tcp port 8080 # SYN-ACK leaves on another interfaceFix
Fix the return route on the server.
Prevent it
Open ports in the same change that adds the service.
Now learn it: break and fix it yourself in Works locally, not from the load balancer, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
Connection refused
curl: (7) Failed to connect to 10.0.1.10 port 8080 after 0 ms: Couldn't connect to server
What it means
The client reached the host, and the host answered at once that nothing accepts connections on that port (a TCP reset). The network works; the problem is on the server side of that port.
Causes, most likely first
Nothing listens on that address and port: the service is down or on another port.
Check
sudo ss -tlnp 'sport = :8080' # no line: nothing listens systemctl status SERVICEFix
Start the service, or fix the port the client uses.
The service listens on 127.0.0.1 only, so it refuses connections from other hosts.
Check
sudo ss -tlnp 'sport = :8080' # 127.0.0.1:8080 or [::1]:8080: local onlyFix
Bind it to the private IP (0.0.0.0 only if it must be reachable everywhere) and restart.
localhost resolved to ::1 while the service listens on 127.0.0.1 only.
Check
curl -v http://localhost:8080 # Trying [::1]:8080 then refusedFix
Use 127.0.0.1 in the client, or make the service listen on both.
A firewall REJECT rule. It looks the same as a closed port.
Check
sudo ss -tlnp 'sport = :8080' # it does listen sudo nft list ruleset | grep -i rejectFix
Allow the port in the firewall.
Prevent it
Check the Local Address column after every deploy.
Now learn it: break and fix it yourself in Listening on 127.0.0.1 only, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
sudo: unable to resolve host
sudo: unable to resolve host web-02: Name or service not known
What it means
sudo looks up the machine's own hostname and could not resolve it. It is a warning, but sudo waits for the lookup to time out, so every sudo is slow. It usually follows a rename.
Cause
The new hostname is not in /etc/hosts.
Check
hostname getent hosts $(hostname) # no output: this is your causeFix
sudo sed -i 's/old-name/new-name/' /etc/hosts.
Prevent it
Rename with hostnamectl set-hostname and update /etc/hosts in the same step; on cloud images set the name through cloud-init, which can rewrite /etc/hosts.
Now learn it: break and fix it yourself in sudo: unable to resolve host, then take Level 11 · Networking. Open in the interactive reference · Link to this answer
Networking
SSL certificate problem: certificate is not yet valid
curl: (60) SSL certificate problem: certificate is not yet valid
What it means
Every certificate has a "not before" date. This machine's clock says it is earlier than that, so the certificate looks like it is from the future. When all TLS fails at once, the clock is almost always the cause.
Causes, most likely first
The system clock is behind.
Check
timedatectl # System clock synchronized: no, and a wrong time chronyc tracking # Rocky (chrony): the offsetFix
Ubuntu:
sudo timedatectl set-ntp true(systemd-timesyncd). Rocky:sudo systemctl enable --now chronyd;sudo chronyc makestepfor a large offset.The certificate was issued minutes ago and this clock is slightly behind.
Check
echo | openssl s_client -connect HOST:443 -servername HOST 2>/dev/null | openssl x509 -noout -startdate # compare with date -uFix
Sync the clock as above.
Prevent it
Run an NTP client on every machine; alert on clock offset.
Now learn it: break and fix it yourself in Certificate is not yet valid, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Users and security
Users and security
is not in the sudoers file
alice is not in the sudoers file.
What it means
sudo checked its rules and found none for this user or any group they are in. It refuses and logs the attempt.
Causes, most likely first
No rule names the user or one of their groups (sudo on Ubuntu, wheel on Rocky).
Check
groups alice # no sudo or wheel sudo -l -U alice # as an admin: not allowedFix
sudo usermod -aG sudo alice(wheel on Rocky), or a narrow rule in /etc/sudoers.d via visudo.Just added to the group, but the session still has the old groups.
Check
groups alice # lists sudo id # in alice's session: sudo is missingFix
Log out and in again.
Prevent it
Grant admin rights through a group, reviewed regularly.
Now learn it: break and fix it yourself in Added to a group, lost the others · Sorry, user deploy is not allowed to execute, then take Level 04 · Users, groups and sudo. Open in the interactive reference · Link to this answer
Users and security
Sorry, user is not allowed to execute
Sorry, user deploy is not allowed to execute '/usr/bin/systemctl restart orders' as root on web-01.
What it means
The user has sudo rules, but none matches this exact command line. sudo compares the full path and arguments with each rule.
Causes, most likely first
The rule names a different command line: another path (/bin or /usr/bin), unit name (orders or orders.service) or arguments.
Check
sudo -l -U deploy # the exact commands allowed; compare letter by letterFix
Update the rule to the exact command, and check it with
visudo -c.A later rule for the same user overrides it: in sudoers the last match wins.
Check
sudo grep -rn deploy /etc/sudoers /etc/sudoers.d # read the orderFix
Remove or reorder the later rule.
Prevent it
Keep CI sudo rules in version control, next to the units they restart.
Now learn it: break and fix it yourself in Sorry, user deploy is not allowed to execute, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
sudo: a terminal is required to read the password
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
What it means
sudo needs a password for this command and has no terminal to ask on, as in cron, CI or ssh host command. So it stops.
Cause
sudo needs a password and there is no terminal to ask on.
Check
sudo -l -U deploy # the rule has no NOPASSWD sudo -n true && echo no password needed # as deploy: failsFix
Allow the exact command without a password, in a drop-in edited with
sudo visudo -f /etc/sudoers.d/deploy:deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart orders. For one interactive run:ssh -t HOST sudo COMMAND. Never pipe a password intosudo -S.
Prevent it
Give automation NOPASSWD rules for the commands it needs and nothing more; never pipe a password into sudo -S.
Now learn it: break and fix it yourself in Sorry, user deploy is not allowed to execute · sudo: parse error in sudoers, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
sudo: parse error in sudoers
>>> /etc/sudoers.d/deploy: syntax error near line 2 <<<
What it means
visudo (or sudo itself) found a syntax error in a sudoers file. sudo refuses to run with broken rules, so it is broken for everyone until the file is fixed.
Causes, most likely first
A syntax error in any sudoers file (missing colon after NOPASSWD, a typo).
Check
visudo -c # as root, or pkexec visudo -c: names the file and lineFix
Fix the file as root (console, rescue boot, or pkexec), then
visudo -c.A sudoers file with the wrong mode or owner.
Check
ls -l /etc/sudoers.d # not 440 root rootFix
chmod 440andchown root:rootthe file, thenvisudo -c.
Prevent it
Edit only with visudo -f; keep a root session open while testing.
Now learn it: break and fix it yourself in sudo: parse error in sudoers, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for '/home/ubuntu/.ssh/id_ed25519' are too open.
What it means
ssh refuses to use a private key that other users can read, because then it is not private. 0644 means everyone on the machine can read it.
Cause
The private key is readable by group or others.
Check
ls -l ~/.ssh # -rw-r--r-- on the key: this is your causeFix
chmod 600 ~/.ssh/id_ed25519, and consider the key exposed if others could log in to this machine.
Prevent it
Copy keys with install -m 600, not cp.
Now learn it: break and fix it yourself in UNPROTECTED PRIVATE KEY FILE, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
Permission denied (publickey)
deploy@db-01: Permission denied (publickey).
What it means
The server allows only key logins, and none of the keys the client offered was accepted for that user. The client cannot see why; the server's log usually says.
Causes, most likely first
Wrong user for the image: ubuntu on Ubuntu cloud images, rocky on Rocky.
Check
ssh -v deploy@db-01 2>&1 | grep 'Authenticating to' # the user and host you really usedFix
Log in as the image's user first.
The client did not offer the key (wrong file, too-open mode, another key in the agent).
Check
ssh -v deploy@db-01 2>&1 | grep -e Offering -e 'Authentications that can continue' # no Offering line for your key: the client never sent itFix
Name the key:
ssh -i ~/.ssh/id_ed25519, or IdentityFile in ~/.ssh/config; key mode 600.The key is not in that user's authorized_keys, or StrictModes rejected the file.
Check
sudo journalctl -u ssh -n 20 # on the server (sshd on Rocky): bad ownership or modesFix
Add the public key; fix modes: ~/.ssh 700, authorized_keys 600.
On Rocky/RHEL, authorized_keys has the wrong SELinux label.
Check
ls -Z /home/deploy/.ssh/authorized_keys # not ssh_home_tFix
sudo restorecon -Rv /home/deploy/.ssh.The server refuses the key type: old ssh-rsa SHA-1 signatures are off in recent OpenSSH.
Check
sudo journalctl -u ssh -n 20 # a refused signature algorithmFix
Make an ed25519 key rather than re-enabling ssh-rsa on the server.
Prevent it
Distribute keys with configuration management.
Now learn it: break and fix it yourself in UNPROTECTED PRIVATE KEY FILE · Authentication refused: bad ownership or modes, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
Authentication refused: bad ownership or modes
Authentication refused: bad ownership or modes for directory /home/deploy/.ssh
What it means
This is the server's side of a refused key: sshd (StrictModes) refuses authorized_keys when the home folder, ~/.ssh or the file can be written by someone else, because they could add their own key.
Cause
Home, ~/.ssh or authorized_keys is writable by group or others, or owned by someone else.
Check
ls -ld /home/deploy /home/deploy/.ssh # w for group or others, or another owner ls -l /home/deploy/.sshFix
chmod 755home (or 750), 700 ~/.ssh, 600 authorized_keys, all owned by the user.
Prevent it
Never chmod -R a home folder.
Now learn it: break and fix it yourself in Authentication refused: bad ownership or modes, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
REMOTE HOST IDENTIFICATION HAS CHANGED
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
What it means
ssh remembers each server's host key in known_hosts. This server now shows a different key, so ssh stops: either the server was rebuilt, or someone is in the middle of the connection.
Causes, most likely first
The server was rebuilt or reinstalled, or its address now belongs to another machine.
Check
ssh-keygen -F db-01 # the key you saved ssh-keyscan db-01 | ssh-keygen -lf - # the key it shows now; compare with the server's consoleFix
Once you know the change is expected:
ssh-keygen -R db-01(and its IP address), then connect and accept the new key.Someone is intercepting the connection: rare, but this is what the check is for.
Check
ssh-keyscan db-01 | ssh-keygen -lf - # differs from the fingerprint on the server's consoleFix
Do not connect; investigate the network path.
Prevent it
When you rebuild a server, share its new host key fingerprint; never switch off StrictHostKeyChecking to make the warning go away.
Now learn it: break and fix it yourself in UNPROTECTED PRIVATE KEY FILE, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
Secrets file readable by everyone
-rw-r--r-- 1 root root /etc/payments/payments.env
What it means
-rw-r--r-- (644) means every user on the machine can read the file. For a file of credentials that is a leak waiting to happen, even if nobody has read it yet.
Causes, most likely first
Created with the default umask, or copied without setting the mode.
Check
ls -l /etc/payments/payments.env # -rw-r--r-- systemctl show -p User payments # who needs to read itFix
sudo chown root:payments FILE && sudo chmod 640 FILE, then restart the service to prove it still reads it.It is loaded by systemd itself with EnvironmentFile=, so the service user does not need to read it at all.
Check
systemctl cat payments | grep -i environmentfile # it is listedFix
systemd reads it as root, so
root:rootmode 600 is enough.
Prevent it
Install secrets with install -m 640 -o root -g SERVICE, or use a secrets manager.
Now learn it: break and fix it yourself in A world-readable secrets file, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
Internal service listening on 0.0.0.0
LISTEN 0 511 0.0.0.0:6379 0.0.0.0:*
What it means
0.0.0.0:6379 in the Local Address column means Redis accepts connections on every network interface, not only from this machine.
Causes, most likely first
bind 0.0.0.0 in its config.
Check
sudo ss -tlnp # 0.0.0.0 or [::] in Local Address: every interfaceFix
Bind to 127.0.0.1 (or the private interface) and restart.
protected-mode or auth turned off, so nothing stops a stranger once they reach it.
Check
grep -E '^(bind|protected-mode|requirepass)' /etc/redis/redis.conf # values only you see; do not paste themFix
Require auth, keep protected-mode on, and keep a firewall as a second layer.
Prevent it
Review ss -tlnp in every security check; keep a firewall as a second layer.
Now learn it: break and fix it yourself in Redis open to the network, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
A user lost their groups after usermod
groups=1002(alice),1003(developers)
What it means
usermod -G sets the list of supplementary groups to exactly what you give it. Without -a it removes every group you did not list, so access through docker, sudo and others is gone.
Cause
usermod -G without -a replaced every supplementary group.
Check
id alice # only the groups you just named grep alice /etc/groupFix
Add back what was lost:
sudo usermod -aG docker,sudo alice.
Prevent it
Always use usermod -aG (or gpasswd -a).
Now learn it: break and fix it yourself in Added to a group, lost the others, then take Level 04 · Users, groups and sudo. Open in the interactive reference · Link to this answer
Users and security
This account is currently not available
This account is currently not available.
What it means
The account's login shell is nologin, which prints this line and exits. Service accounts are made that way on purpose, so nobody logs in as them.
Cause
The account's shell is /usr/sbin/nologin (/sbin/nologin on Rocky).
Check
getent passwd www-data # the last field is the shellFix
Run the command as that user instead:
sudo -u www-data COMMAND, or for a shell oncesudo -u www-data bash.
Prevent it
Leave service accounts on nologin, and give people their own accounts.
Now learn it: break and fix it yourself in Added to a group, lost the others, then take Level 04 · Users, groups and sudo. Open in the interactive reference · Link to this answer
Users and security
SSH brute force in auth.log
Failed password for invalid user admin from 203.0.113.77 port 51544 ssh2
What it means
Bots across the internet try common user names and passwords against every reachable sshd. "invalid user admin" means that account does not even exist here. The real question is whether passwords are accepted at all, and whether any attempt succeeded.
Causes, most likely first
Password logins are enabled on an internet-facing sshd.
Check
sudo sshd -T | grep -i passwordauthentication # yes: the value in effect sudo grep 'Accepted password' /var/log/auth.log # /var/log/secure on Rocky; any line: someone got in, treat it as an incidentFix
PasswordAuthentication no,sudo sshd -t,sudo systemctl reload ssh(sshd on Rocky).A drop-in in sshd_config.d (such as 50-cloud-init.conf) overrides the main file: the first value read wins.
Check
grep -ri passwordauthentication /etc/ssh/sshd_config.d/ # a yes that winsFix
Set it in that drop-in, or in one that sorts first. Add fail2ban: on Ubuntu its sshd jail is on after install; on Rocky it comes from EPEL and the jail must be enabled.
Prevent it
Keys only, no root login, fail2ban, and ideally SSH only from a VPN or bastion.
Now learn it: break and fix it yourself in SSH brute force, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Users and security
SSL certificate problem: certificate has expired
curl: (60) SSL certificate problem: certificate has expired
What it means
The client checked the certificate's "not after" date and it has passed, so it refuses the connection. What matters is the certificate the server actually sends, which may not be the file you renewed.
Causes, most likely first
Renewal stopped: the timer is disabled or renewal fails.
Check
sudo certbot certificates # expired on disk too systemctl list-timers --all | grep -i certbot # missing or never ranFix
sudo certbot renew && sudo systemctl reload nginx, then enable the timer your install has: certbot.timer (apt), certbot-renew.timer (EPEL on Rocky) or snap.certbot.renew.timer (snap).Renewed, but the server was not reloaded, or it serves a copy of the old file.
Check
echo | openssl s_client -connect shop.example:443 -servername shop.example 2>/dev/null | openssl x509 -noout -enddate # what clients get sudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/shop.example/fullchain.pem # newer than the served date: this is your causeFix
Reload the server, and point it at /etc/letsencrypt/live/..., not a copy.
The server sends an expired intermediate certificate.
Check
echo | openssl s_client -connect shop.example:443 -servername shop.example -showcerts 2>/dev/null | grep -A1 ' s:' # the chain it sendsFix
Serve fullchain.pem, not an old chain file.
The client's clock is ahead.
Check
timedatectl # on the clientFix
Sync the client's clock.
Prevent it
Monitor the expiry of what is served (openssl s_client), not just that renewal ran.
Now learn it: break and fix it yourself in certificate has expired, then take Level 12 · Security hardening. Open in the interactive reference · Link to this answer
Boot, kernel and packages
Boot, kernel and packages
Could not get lock /var/lib/dpkg/lock-frontend
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2810 (unattended-upgr)
What it means
apt takes a lock so that only one package operation runs at a time. Another process holds it, here unattended-upgrades (pid 2810), so this apt waits or stops.
Causes, most likely first
Another apt or dpkg is running: often unattended-upgrades on a new server.
Check
ps -fp 2810 # the process holding the lock systemctl status unattended-upgradesFix
Wait for it to finish, then retry. Never delete lock files: the lock goes when its process exits.
cloud-init is still installing packages on first boot.
Check
cloud-init status # running: first-boot setup is not doneFix
cloud-init status --wait, then retry.
Prevent it
In automation, wait for the lock (apt-get -o DPkg::Lock::Timeout=300).
Now learn it: break and fix it yourself in Could not get lock /var/lib/dpkg/lock-frontend, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
dpkg was interrupted
E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.
What it means
dpkg records each install step; the last one did not finish, so packages are half configured. apt refuses to do anything else until that is completed.
Cause
An install was killed, or lock files were removed while it ran.
Check
sudo dpkg --audit # the half-configured packagesFix
sudo dpkg --configure -a, thensudo apt -f install.
Prevent it
Do not kill apt or delete its locks.
Now learn it: break and fix it yourself in Could not get lock /var/lib/dpkg/lock-frontend, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
E: Unable to locate package
E: Unable to locate package nodejs-lts
What it means
apt looked the name up in its package lists and found nothing. The lists are a local copy downloaded by apt update, so the package may exist but not in what this machine knows.
Causes, most likely first
The package lists are old or were never downloaded (a fresh image).
Check
apt-cache policy nodejs # no candidate, or nothing at allFix
sudo apt update, then install again.The name is wrong, or different on this release.
Check
apt-cache search nodejs # the real namesFix
Use the real name from apt-cache search.
It lives in a repository you have not added (universe, or the vendor's own).
Check
apt-cache policy # universe or the vendor's repository missingFix
sudo add-apt-repository universe, or add the vendor's repository.
Prevent it
Start scripts for fresh servers with apt-get update.
Now learn it: break and fix it yourself in Could not get lock /var/lib/dpkg/lock-frontend, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
apt: NO_PUBKEY, repository is not signed
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 1A2B3C4D5E6F7A8B
What it means
apt checks every repository's signature. It could not, because the key that signed this repository (ID ending 1A2B3C4D5E6F7A8B) is not in the keyring the repository is set to trust.
Causes, most likely first
The repository's signing key is not installed, or the vendor rotated it.
Check
gpg --show-keys /etc/apt/keyrings/vendor.gpg # no key ends with the NO_PUBKEY idFix
Download the vendor's current key, check its fingerprint against the one they publish, and
sudo gpg --dearmor -o /etc/apt/keyrings/vendor.gpg.The sources line points at a keyring (signed-by=) that is missing or holds the old key.
Check
grep -ri signed-by /etc/apt/sources.list /etc/apt/sources.list.d/ # Signed-By: in .sources files ls -l /etc/apt/keyrings /usr/share/keyrings # the file it names is there?Fix
sudo install -d -m 0755 /etc/apt/keyrings, put the key there, and point the line at it:deb [signed-by=/etc/apt/keyrings/vendor.gpg] URL SUITE main, thensudo apt update.
Prevent it
One keyring per repository, named with signed-by=; apt-key is deprecated.
Now learn it: break and fix it yourself in Could not get lock /var/lib/dpkg/lock-frontend, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
Release file is not valid yet
E: Release file for http://archive.ubuntu.com/ubuntu/dists/noble-updates/InRelease is not valid yet (invalid for another 3d 2h 41min 7s). Updates for this repository will not be applied.
What it means
Repository index files carry a date. This machine's clock is earlier than that date, so apt treats the file as from the future and refuses it. "invalid for another 3d" says how far behind the clock is.
Cause
The system clock is in the past (often a restored snapshot or a VM without NTP).
Check
timedatectl # the wrong date, System clock synchronized: noFix
sudo timedatectl set-ntp true.
Prevent it
Keep NTP on everywhere; snapshots restored to VMs often have old clocks.
Now learn it: break and fix it yourself in Certificate is not yet valid, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
System restart required
*** System restart required ***
What it means
The package manager installed a new kernel or core library that only takes effect after a reboot. Until then the old one runs, so scanners still see it.
Cause
A kernel or libc update only applies after a reboot.
Check
uname -r # the running kernel, older than the installed one cat /run/reboot-required.pkgs # Ubuntu: what asked for it sudo dnf needs-restarting -r # Rocky: whether a reboot is neededFix
Reboot in a window; check
systemctl --failedafterwards.
Prevent it
Schedule reboots (or livepatch) as part of patching.
Now learn it: break and fix it yourself in Patched, but still vulnerable, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Boot, kernel and packages
Routing or NAT stops after a reboot
net.ipv4.ip_forward = 0
What it means
net.ipv4.ip_forward = 0 means the kernel will not pass packets from one interface to another. A gateway, VPN or container host needs it on, and it was off again after the reboot.
Causes, most likely first
The setting was changed with sysctl -w and never persisted.
Check
grep -r ip_forward /etc/sysctl.conf /etc/sysctl.d # nothing: this is your causeFix
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-forward.conf && sudo sysctl --system.A file read later sets it back: sysctl.d files apply in name order, and the last value wins.
Check
systemd-analyze cat-config sysctl.d | grep -e '^# /' -e ip_forward # every file in order: the last ip_forward winsFix
Remove the later line (99-sysctl.conf is /etc/sysctl.conf).
Prevent it
Persist every kernel setting in /etc/sysctl.d, and reboot-test.
Now learn it: break and fix it yourself in The NAT gateway stopped routing, then take Level 13 · Boot, kernel and packages. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
Rocky Linux and RHEL
dnf: Unable to find a match
Error: Unable to find a match: htop
What it means
dnf searched every enabled repository and found no package by that name. On Rocky many common tools are not in the base repositories.
Causes, most likely first
The package lives in EPEL, which is not enabled.
Check
dnf repolist # no epelFix
sudo dnf install -y epel-release, then install again.It needs CRB (PowerTools on Rocky 8), which is off by default.
Check
dnf repolist # epel listed, crb notFix
sudo dnf config-manager --set-enabled crb(powertools on Rocky 8).A typo, or a package name that differs from Debian's.
Check
dnf search htop dnf provides '*/htop' # the package that ships the fileFix
Install the name dnf shows.
An exclude= line in dnf.conf or a repo file hides it.
Check
grep -r exclude /etc/dnf/dnf.conf /etc/yum.repos.d/Fix
Change it only once you know why it was added.
Prevent it
Enable the repositories you rely on in the server image.
Now learn it: break and fix it yourself in dnf: Unable to find a match, then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
SELinux denial: 403 with correct permissions
avc: denied { read } for pid=1312 comm="nginx" name="index.html" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0
What it means
An AVC denial is SELinux saying no. Read it as: process nginx (domain httpd_t, in scontext) tried to read a file labelled user_home_t (tcontext), and the policy does not allow that. permissive=0 means it was really blocked. File modes are not involved.
Causes, most likely first
Files carry the wrong SELinux label. mv keeps the label from where the file was, so files moved from a home folder stay user_home_t.
Check
ls -Z /srv/shop # user_home_t, not httpd_sys_content_t sudo ausearch -m avc -ts recent | audit2why # says a label fixes itFix
sudo restorecon -Rv /srv/shopif the path has a default; otherwise see the next cause.A path outside the policy's defaults (/srv, /data), so restorecon has no web label to apply.
Check
matchpathcon /srv/shop # var_t or default_tFix
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/shop(/.*)?' && sudo restorecon -Rv /srv/shop.A boolean is off, such as httpd_can_network_connect for nginx proxying to a backend (a 502).
Check
sudo ausearch -m avc -ts recent | audit2why # names the boolean (policycoreutils-python-utils)Fix
sudo setsebool -P httpd_can_network_connect 1. Neversetenforce 0, and do not feed denials to audit2allow blindly: it allows whatever was denied.
Prevent it
Never setenforce 0 as a fix; use cp (not mv) into labelled places, or define fcontext rules for custom paths.
Now learn it: break and fix it yourself in 403 with correct permissions: SELinux, then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
bind() failed (13: Permission denied) on a custom port
nginx: [emerg] bind() to 0.0.0.0:8090 failed (13: Permission denied)
What it means
nginx tried to listen on port 8090 and the kernel said no. The master process runs as root, so it is not a normal permission: on Rocky/RHEL, SELinux lets the web server bind only ports labelled http_port_t.
Causes, most likely first
SELinux allows httpd_t to bind only http_port_t ports, and 8090 is not one.
Check
sudo ausearch -m avc -ts recent # name_bind denied: SELinux sudo semanage port -l | grep -w 8090 # not listed, or under another typeFix
sudo semanage port -a -t http_port_t -p tcp 8090(semanage is in policycoreutils-python-utils). If it says the port is already defined, use -m instead of -a.A non-root process on a port below 1024 (any distribution).
Check
ps -o user= -p $(pgrep -o nginx) # not rootFix
Use a port above 1024 behind a proxy, or
AmbientCapabilities=CAP_NET_BIND_SERVICEin the unit.
Prevent it
Include port labels in provisioning when you use non-standard ports.
Now learn it: break and fix it yourself in bind() failed (13: Permission denied), then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
firewalld drops traffic to a new port
curl: (7) Failed to connect to app-01 port 8080: No route to host
What it means
Rocky's firewall, firewalld, rejects connections to ports that are not open in the zone, and the client sees "No route to host" at once. The service is fine; local curl works because the firewall does not filter the machine's own loopback traffic.
Causes, most likely first
The port is not open in the zone the interface is in.
Check
sudo firewall-cmd --get-active-zones # the zone the interface is in sudo firewall-cmd --zone=public --list-all # 8080/tcp not in ports or servicesFix
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp && sudo firewall-cmd --reload. For a known service,--add-service=httpreads better.Opened at runtime only, lost after --reload or reboot.
Check
sudo firewall-cmd --permanent --list-ports # missing here while --list-ports shows itFix
sudo firewall-cmd --runtime-to-permanent.Open on the host, but a cloud security group drops it: that times out instead of No route to host.
Check
sudo tcpdump -ni any tcp port 8080 # no SYN arrivesFix
Allow the port from the client's subnet in the security group. Do not stop firewalld to make it work.
Prevent it
Always use --permanent plus --reload (or --runtime-to-permanent).
Now learn it: break and fix it yourself in firewalld blocks the new port, then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
resize2fs: Bad magic number in super-block
resize2fs: Bad magic number in super-block while trying to open /dev/mapper/rl-root
What it means
resize2fs only understands ext2/3/4. It read the start of the volume, did not find an ext4 superblock (the "magic number"), and stopped. The volume is fine; it is another file system.
Cause
The file system is XFS, Rocky's default, not ext4.
Check
df -hT / # xfsFix
sudo xfs_growfs /. Next time uselvextend -r, which picks the right tool.
Prevent it
Use lvextend -r, which picks the right tool for the file system.
Now learn it: break and fix it yourself in Grow / on LVM and XFS, then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Rocky Linux and RHEL
lvextend: Insufficient free space
Insufficient free space: 10240 extents needed, but only 7423 available
What it means
LVM sizes are counted in extents (blocks of usually 4 MiB). You asked for 10240 more, and the volume group has only 7423 free.
Cause
The volume group has less free space than requested.
Check
sudo vgs # VFree sudo pvs # which disks have roomFix
Ask for less (
-l +100%FREE), or add a disk: pvcreate, vgextend, thenlvextend -r.
Prevent it
Watch VFree; plan growth per volume.
Now learn it: break and fix it yourself in Grow / on LVM and XFS, then take Level 16 · Rocky Linux and RHEL. Open in the interactive reference · Link to this answer
Performance
Performance
High load, idle CPU: NFS server not responding
nfs: server nfs-02 not responding, still trying
What it means
The kernel's NFS client cannot reach the server and, for a hard mount, keeps retrying forever. Every process that touches the mount waits in D state (uninterruptible), which counts in the load average, so load climbs while CPUs sit idle.
Cause
A hard NFS mount whose server is down or unreachable.
Check
sudo dmesg | grep -i nfs # not responding, still trying ps -eo pid,stat,cmd | grep ' D' # processes stuck on the mount df -hl # skips network mounts, so it does not hangFix
Fix the server or the network; to free the client,
sudo umount -f -l /mnt/reports, then fix or remove its fstab line.
Prevent it
Mount non-essential shares with _netdev,nofail and x-systemd.automount; use df -l in scripts and monitoring.
Now learn it: break and fix it yourself in High load, idle CPU: a hung NFS mount, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
Memory that only grows
queue-worker 2.40G RSS, +120 MB/min
What it means
RSS is the memory a process really holds. It climbs steadily and never comes down, until the machine swaps or the OOM killer acts.
Causes, most likely first
A leak in the program.
Check
ps -o pid,rss,etime,cmd -p PID; sleep 60; ps -o pid,rss,etime,cmd -p PID # RSS up every timeFix
Contain it:
sudo systemctl set-property NAME MemoryMax=1Gwith Restart=always, and report the leak with the numbers.Not a leak: a heap or cache that grows to its cap (a JVM up to -Xmx) and then stays flat.
Check
ps aux --sort=-rss | head # watch for an hour: it levels offFix
Set the cap to fit the machine.
Prevent it
MemoryMax= on every service; alert on RSS growth, not only on free memory.
Now learn it: break and fix it yourself in A slow memory leak, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
swapon: read swap header failed
swapon: /swapfile: read swap header failed
What it means
swapon read the start of the file looking for a swap signature and found none. A file becomes usable as swap only after mkswap writes that header.
Cause
mkswap was not run on the file.
Check
file /swapfile # data, not swap fileFix
sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile, then a line in /etc/fstab.
Prevent it
Script swap creation: fallocate, chmod 600, mkswap, swapon, fstab.
Now learn it: break and fix it yourself in No swap, and memory is tight, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
swapon: insecure permissions, 0600 suggested
swapon: /swapfile: insecure permissions 0644, 0600 suggested.
What it means
Swap holds pages of memory, secrets included. swapon warns that other users can read this file and suggests 0600. It still works, but anyone could read memory contents.
Cause
The swap file is readable by others.
Check
ls -l /swapfile # -rw-r--r--Fix
sudo chmod 600 /swapfile.
Prevent it
chmod 600 before mkswap.
Now learn it: break and fix it yourself in No swap, and memory is tight, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
High load, idle CPU (I/O wait)
%Cpu(s): 5.6 us, 1.4 sy, 0.0 ni, 0.0 id, 81.0 wa
What it means
wa in top is the share of time CPUs sit idle waiting for disk. Processes waiting on I/O are in D state and count in the load, so load is high while the CPUs do almost nothing.
Causes, most likely first
A saturated disk: a backup, rsync or updatedb is reading or writing as fast as it can.
Check
iostat -x 1 5 # %util near 100 and a high await (sysstat) sudo iotop -o # which processFix
sudo ionice -c3 -p PIDfor the I/O hog, or reschedule it.A cloud volume at its IOPS or throughput limit (burst credits used up).
Check
iostat -x 1 5 # flat r/s+w/s at the volume's limit with modest %utilFix
Raise the volume's IOPS or throughput, or move the load.
A hung network mount.
Check
ps -eo pid,stat,cmd | grep ' D' # stuck on an NFS pathFix
See NFS server not responding.
Prevent it
Run backups with ionice -c3 nice -n19, off-peak, or on a separate disk.
Now learn it: break and fix it yourself in High load, idle CPU, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
Swap thrashing
si 1840 so 2210
What it means
si and so in vmstat are pages swapped in and out per second. Both high at once means the working set does not fit in RAM: the kernel keeps moving pages to disk and back, and everything waits on that.
Cause
The working set does not fit in RAM.
Check
vmstat 1 5 # si and so both high free -h # little available top -o %MEM # the biggest userFix
Cap the hog:
sudo systemctl set-property NAME MemoryMax=1G, or stop it; add RAM if the load is real.
Prevent it
Set MemoryMax= per service; alert on swap-in rate.
Now learn it: break and fix it yourself in Swap thrashing, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
Main process exited, code=killed, status=9/KILL
reports.service: Failed with result 'oom-kill'.
What it means
systemd says the service's main process died from signal 9 (SIGKILL), and Result says who decided: oom-kill means memory. The service then restarts and dies again.
Causes, most likely first
The kernel OOM killer or a MemoryMax= limit.
Check
systemctl show reports -p Result -p NRestarts # Result=oom-kill sudo journalctl -k | grep -i oomFix
Fit the service to memory (heap, workers), or give it more.
systemd-oomd under memory pressure, where it is enabled.
Check
journalctl -u systemd-oomd # Killed ... due to memory pressureFix
Lower the memory use, or tune oomd for that slice.
A stop that ran past TimeoutStopSec=: systemd sends SIGKILL.
Check
systemctl show reports -p Result # Result=timeoutFix
Find why stopping hangs before raising TimeoutStopSec=.
Someone's kill -9.
Check
systemctl show reports -p Result # Result=signal journalctl -u reports | grep -i killFix
Find who sent it.
Prevent it
Never protect one service with oom_score_adj at the cost of the database.
Now learn it: break and fix it yourself in Killed by the OOM killer, then take Level 14 · Performance. Open in the interactive reference · Link to this answer
Performance
Too many open files
accept4() failed (24: Too many open files)
What it means
Every open file and network connection uses a file descriptor, and each process has a limit. The service reached it (EMFILE, code 24), so new connections or files fail.
Causes, most likely first
The service's soft open-files limit (1024 by default) is too low for its load.
Check
cat /proc/$(pgrep -o gateway)/limits | grep 'open files' # the limit the process really has ls /proc/$(pgrep -o gateway)/fd | wc -l # at the limitFix
Drop-in
[Service] LimitNOFILE=65535, daemon-reload, restart.A file descriptor leak.
Check
ls /proc/$(pgrep -o gateway)/fd | wc -l # keeps climbing at low traffic: a leakFix
Fix the program; a bigger limit only delays it.
The program's own cap, such as nginx worker_rlimit_nofile.
Check
grep -r worker_rlimit_nofile /etc/nginx/Fix
Raise that setting too.
Prevent it
limits.conf does not apply to services: set LimitNOFILE= in the unit.
Now learn it: break and fix it yourself in Too many open files, then take Level 14 · Performance. Open in the interactive reference · Link to this answer