Debugging cron is a discipline, not a guessing game: test the command manually first, run crond in the foreground with cron -n, check exit codes, and use sentinel files to prove execution. This episode also introduces crontab.guru and a testing strategy with near-term schedules.

In episode 6 we learned that environment is the leading cause of job failures. Now we build a debugging discipline — a structured sequence of steps that breaks a cron problem into small pieces you can test one at a time.
The principle is simple: debug from the inside out. Test the command first, then the script, then the crontab, then the daemon. Each layer that passes narrows down where the problem is.
Always run the command exactly as it appears in crontab, from the terminal:
/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
echo "exit code: $?"Watch for two things: is the output correct, and is the exit code 0. A non-0 exit code means something failed at the command level — before cron even gets involved.
Run the script with the same environment cron uses (remember episode 6):
env -i /usr/bin/sh -c '/usr/local/bin/backup.sh'
echo "exit code: $?"env -i clears the entire environment — the closest simulation of cron's conditions. If it fails here, the problem is the environment.
Exit codes are the language scripts use to communicate with cron:
0 = success.0 = failure; the value hints at the error type (e.g. 127 = command not found, 126 = not executable).Also check /var/log/cron to see whether crond actually executed that line:
grep backup /var/log/cronA sentinel file proves that a job actually executed — and when:
* * * * * touch /tmp/cron-ran-$(date +%Y%m%d-%H%M).flagAfter one minute, check:
ls -l /tmp/cron-ran-*.flagIf the file appears, the schedule and daemon are working; the problem is in the command. If it doesn't appear, the problem is in the schedule or the daemon.
Cronie provides cron -n, which runs crond in the foreground — ideal for directly observing what happens:
sudo systemctl stop crond
sudo crond -n -l 8Log level 8 (full debug) is printed to the terminal. This is the fastest way to see why a schedule isn't triggering. When you're done, restore the normal daemon:
sudo systemctl start crondcrontab.guru is a popular cron schedule syntax validator. Paste a schedule, and the site explains its meaning in plain language — it also warns about odd combinations like the OR on day-of-month/day-of-week.
The most effective strategy to verify a schedule: use a time that's very close instead of waiting for the scheduled hour:
* * * * * /usr/local/bin/myjob.sh >> /tmp/test.log 2>&1Watch the execution within a minute, fix, then switch to the real schedule. Never debug a 0 2 * * * schedule — waiting until 2 AM is not an efficient way to work.
Tip
The most powerful combination: * * * * * + sentinel file + per-job log. You get feedback within a minute, proof of execution, and an output trail — three things that immediately show which layer the problem is in.
| Symptom | Likely Cause | Test Step |
|---|---|---|
| Job never runs | Wrong schedule / daemon down | crontab -l, cron -n, sentinel |
| Runs but errors | Environment/PATH | env -i, command not found |
| Runs twice | DST / OR time fields | Check logs, revise schedule |
| Output missing | Wrong redirect | Check log file, 2>&1 |
Key takeaways:
cron -n runs crond in the foreground with full debug logging.* * * * * instead of the scheduled hour.In episode 8 we'll cover anacron and system cron directories — how anacron runs missed jobs for machines that are often off, the /etc/anacrontab configuration, and how /etc/cron.hourly|daily|weekly|monthly/ works via run-parts, plus when to use each!