systemd Error: 'Failed with result exit-code' — Cause, Fix, and Troubleshooting Guide
Fix myjob.service: Failed with result 'exit-code' from a systemd timer — non-zero ExecStart, wrong WorkingDirectory/User, and systemd's minimal environment.
- #automation
- #troubleshooting
- #systemd
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
myjob.service: Failed with result 'exit-code'. means a systemd unit ran its ExecStart process, that process exited non-zero, and systemd marked the unit failed. When the unit is triggered by a .timer (systemd’s cron replacement), this is the timer-driven equivalent of a cron job failing — the schedule fired, the service ran, and the command returned an error.
The exit-code result is systemd’s classification: the process started and exited on its own with a non-zero status, as opposed to being killed by a signal (signal), timing out (timeout), or failing to start at all (exec / protocol). Like cron, systemd runs services in a minimal environment with an empty PATH-less context, a specific User, and a WorkingDirectory — so a command that works in your shell can fail here.
The full failure in the journal reads:
Jul 12 04:00:12 host systemd[1]: Starting Nightly backup job...
Jul 12 04:00:12 host myjob[3187]: /usr/local/bin/backup.sh: line 6: aws: command not found
Jul 12 04:00:12 host systemd[1]: myjob.service: Main process exited, code=exited, status=1/FAILURE
Jul 12 04:00:12 host systemd[1]: myjob.service: Failed with result 'exit-code'.
Jul 12 04:00:12 host systemd[1]: Failed to start Nightly backup job.
The status=1/FAILURE line names the exit code (1); the Failed with result 'exit-code' line is systemd’s summary; the backup[3187] line above is the actual error.
Symptoms
systemctl status myjob.serviceshowsActive: failed (Result: exit-code).- Journal contains
Main process exited, code=exited, status=N/FAILUREthenFailed with result 'exit-code'. systemctl list-timersshows the timer firing but the service never completing successfully.- The script runs fine when you execute it by hand but fails under the timer.
- A
Type=oneshotservice is marked failed even though “the work looked done”.
Common Root Causes
1. The ExecStart script exits non-zero
The most direct cause — the command genuinely failed. A set -euo pipefail script tripping on an unset variable, a failed curl, a non-zero pg_dump.
journalctl -u myjob.service -n 20 --no-pager | grep -iE 'error|fail|not found'
/usr/local/bin/backup.sh: line 6: aws: command not found
2. Minimal environment — missing PATH and variables
systemd services start with a restricted environment. /usr/local/bin, version-manager shims, and any variable you set in ~/.bashrc are absent. Exit 127 (command not found) is the classic tell.
systemctl show myjob.service -p Environment -p ExecStart
Environment=
ExecStart={ path=/usr/local/bin/backup.sh ; argv[]=/usr/local/bin/backup.sh ; ... }
An empty Environment= and a script that relies on PATH additions will fail.
3. Wrong WorkingDirectory, User, or ExecStart path
The service runs as the configured User (default root) from WorkingDirectory (default /). Relative paths break, and a script owned/readable only by another user hits permission errors.
status=203/EXEC # ExecStart path wrong or not executable
status=200/CHDIR # WorkingDirectory does not exist
4. Missing EnvironmentFile
The unit expects secrets/config from an EnvironmentFile that is absent or unreadable, leaving required variables unset.
systemctl show myjob.service -p EnvironmentFiles
5. Type=oneshot semantics
For Type=oneshot, systemd considers the service successful only if the process exits 0. Any non-zero exit — including a script that “finished” but returned the status of its last command — is a failure. A trailing command that returns 1 fails the whole unit.
How to Diagnose
Step 1 — Read the unit status; it shows the result and the last log lines.
systemctl status myjob.service --no-pager
● myjob.service - Nightly backup job
Loaded: loaded (/etc/systemd/system/myjob.service; static)
Active: failed (Result: exit-code) since Sun 2026-07-12 04:00:12 UTC
Process: 3187 ExecStart=/usr/local/bin/backup.sh (code=exited, status=1/FAILURE)
Main PID: 3187 (code=exited, status=1/FAILURE)
The Process: line gives the exact status=N and the ExecStart that failed.
Step 2 — Read the full journal for this unit and this run.
journalctl -u myjob.service --since '-1h' --no-pager
Jul 12 04:00:12 host myjob[3187]: /usr/local/bin/backup.sh: line 6: aws: command not found
Jul 12 04:00:12 host systemd[1]: myjob.service: Main process exited, code=exited, status=1/FAILURE
The line above systemd’s summary is the real error.
Step 3 — Confirm the timer is firing and see when it last/next runs.
systemctl list-timers myjob.timer --all --no-pager
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-07-13 04:00:00 UTC 20h left Sun 2026-07-12 04:00:12 UTC 30m ago myjob.timer myjob.service
If LAST shows the timer fired but the service failed, the schedule is fine — the job is the problem.
Step 4 — Run the service on demand to reproduce without waiting for the timer.
sudo systemctl start myjob.service; systemctl is-failed myjob.service
journalctl -u myjob.service -n 5 --no-pager
Step 5 — Reproduce systemd’s minimal environment to catch PATH/env issues:
sudo systemd-run --pty --same-dir --wait \
--property=User=myuser /usr/local/bin/backup.sh
If it fails here but works in your shell, the cause is environment (PATH, missing vars), not logic.
Fixes
Fix the failing command. If the journal named the error, correct it. For command not found, set an explicit PATH or use absolute paths in the unit:
[Service]
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/local/bin/backup.sh
Set the correct User, WorkingDirectory, and absolute ExecStart.
[Service]
Type=oneshot
User=myuser
WorkingDirectory=/opt/jobs
ExecStart=/opt/jobs/backup.sh
Provide environment via EnvironmentFile so secrets and config are present:
[Service]
EnvironmentFile=/opt/jobs/backup.env
ExecStart=/opt/jobs/backup.sh
sudo install -m 600 -o myuser /dev/stdin /opt/jobs/backup.env <<'EOF'
AWS_PROFILE=backup
DATABASE_URL=postgres://user@10.0.0.5/app
EOF
Apply changes and re-test — systemd caches unit files:
sudo systemctl daemon-reload
sudo systemctl start myjob.service
systemctl status myjob.service --no-pager | head -5
Active: inactive (dead) # oneshot succeeded and exited 0
Make the script return a clean status. For Type=oneshot, ensure the script ends with a command that exits 0 on success, and use set -euo pipefail so real failures surface rather than being masked by a trailing echo.
Add controlled restart/notification so a transient failure recovers or alerts:
[Service]
Restart=on-failure
RestartSec=30
What to Watch Out For
- The
status=N/NAMEcode narrows the cause fast:1/FAILURE= script error,127= command not found (PATH),203/EXEC= bad ExecStart path or not executable,200/CHDIR= missing WorkingDirectory,226/NAMESPACE= sandbox/permission setting. - systemd’s environment is minimal like cron’s — do not rely on login-shell PATH or
~/.bashrcvariables. Declare everything in the unit or an EnvironmentFile. Result: exit-codemeans the process exited on its own;signal,timeout, andoom-killare different results with different fixes — read the exact word.- Always
systemctl daemon-reloadafter editing a unit file, or systemd runs the stale version and your fix appears to do nothing. - For
Type=oneshot, the unit fails on any non-zero exit; a script whose last line returns 1 fails the whole job even if the real work succeeded. - The timer and the service are separate units. If
list-timersshows the timer firing but the service fails, debug the.service, not the.timer.
Related Guides
- Cron Error: ‘(CRON) error (grandchild #NNNN failed with exit status 1)’
- Automation Error: Overlapping Cron Runs Cause a Race Condition
- Scheduled Job Orchestration at Scale
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.