Debugging Cron Jobs That Are Not Running
"It's in the crontab but nothing happens" is one of the most frustrating debugging sessions in backend work, because cron fails silently by design — no error dialog, no crash, just... nothing. This guide walks through the checklist, in the order that catches the most common causes first.
Step 1: Confirm the cron service is actually running
Before touching your crontab, rule out the daemon itself:
# Debian / Ubuntu $ systemctl status cron # RHEL / CentOS / Fedora / Amazon Linux $ systemctl status crond # If inactive or failed: $ sudo systemctl start cron $ sudo systemctl enable cron # so it survives a reboot
This is easy to overlook after a server rebuild, a minimal Docker base image, or a fresh cloud instance — cron isn't always installed or enabled by default.
Step 2: Check for a silent syntax error in the crontab
A malformed line doesn't crash cron or throw a visible error — cron just skips that entry. Look for it in the system log:
# View recent cron activity in the system log $ grep CRON /var/log/syslog | tail -20 # Debian/Ubuntu $ journalctl -u crond --since "1 hour ago" # RHEL/CentOS with systemd # List your current crontab to eyeball the syntax $ crontab -l
- Every entry needs exactly 5 time fields before the command — 4 or 6 fields (unless you're using Quartz-style syntax elsewhere) will be rejected.
- Percent signs (
%) are special in crontab — they mean newline unless escaped with\%. A rawdate +\%Y\%m\%dneeds the backslashes. - Comments must start with
#at the start of the line.
Step 3: Verify file and execute permissions
$ ls -l /opt/scripts/backup.sh -rw-r--r-- 1 deploy deploy 812 Jul 11 09:00 backup.sh # ^ missing execute bit — cron will fail to run this $ chmod +x /opt/scripts/backup.sh $ ls -l /opt/scripts/backup.sh -rwxr-xr-x 1 deploy deploy 812 Jul 11 09:00 backup.sh
Also confirm the crontab's owning user actually has permission to read/write any files or directories the script touches — a job in root's crontab writing to a directory only "deploy" owns will fail with a permission error you'll only see in the logs, not on screen.
Step 4: Rule out the classic PATH / environment problem
This is the single most common cause of "works manually, not from cron." Cron provides a minimal environment — typically just PATH=/usr/bin:/bin — with none of your shell profile loaded:
# Temporarily add this entry to see exactly what environment cron gives you * * * * * env > /tmp/cron-env.txt 2>&1 # Compare with your interactive shell's environment $ env > /tmp/shell-env.txt $ diff /tmp/cron-env.txt /tmp/shell-env.txt # Fix: use absolute paths in the script/crontab, or set PATH explicitly # at the top of the crontab file PATH=/usr/local/bin:/usr/bin:/bin */10 * * * * /usr/bin/node /app/sync.js
Step 5: Double-check the schedule actually means what you think
Sometimes cron is running exactly as configured — it's just not the schedule you intended. Common misreadings:
0 0 1,15 * *was meant as "1st AND 15th" but was typed as0 0 1-15 * *which runs every day from the 1st through the 15th.- Assuming the server runs in IST when it's actually configured for UTC (or vice versa) — see our timezone guide for how to confirm this.
- A day-of-month and day-of-week field combined unexpectedly — in standard cron, if both are restricted (not
*), the job runs when either condition matches, which surprises people expecting an AND.
# This does NOT mean "1st of the month AND a Monday" # It means "1st of the month OR any Monday" — a very common trap 0 9 1 * 1
Quick reference checklist
- Is the cron/crond service active? (
systemctl status cron) - Does
crontab -lshow the entry with exactly 5 valid time fields? - Does the script have execute permission and correct file ownership?
- Does the script use absolute paths for every binary and file it touches?
- Is output redirected somewhere you can actually see it (not silently discarded)?
- Does the schedule's day-of-month/day-of-week combination mean OR, not AND, as intended?
- Is the server's timezone what you assumed it was?
Frequently Asked Questions
The most common causes are: the cron service itself is stopped, the crontab has a syntax error causing that line to be silently ignored, the script lacks execute permissions, or the schedule expression does not mean what you think it means. Check systemctl status cron first, then verify the crontab syntax and file permissions.
Run systemctl status cron on Debian/Ubuntu or systemctl status crond on RHEL/CentOS/Fedora. If it shows "inactive" or "failed," start it with systemctl start cron (or crond) and enable it on boot with systemctl enable cron.
This is almost always an environment difference. Cron runs with a minimal PATH and no shell profile loaded, so commands and relative file paths that work in your interactive terminal often fail silently under cron. Use absolute paths for every binary and file reference in the script.