Cron job not running / crontab not executing

You put a line in crontab, waited, and nothing happened. Most of the time the schedule is fine — the environment around it is not.

Decode the expression before blaming cron

A surprising number of "not running" reports are schedules that never meant what the author thought. Paste the five fields (or an @hourly-style shortcut) into the Cron Expression Explainer and read the plain-English sentence plus the next run times in local and UTC. From a script or CI, the same breakdown is a keyless JSON call:

curl -sG 'https://api.oddlathe.com/v1/cron/explain' \
  --data-urlencode 'expr=0 9 * * 1-5' \
  --data-urlencode 'tz=Europe/London' \
  --data-urlencode 'n=5'

See also cron every 5 minutes and @reboot.

Checklist when nothing fires

CheckCommand / placeTypical miss
Right crontabcrontab -l as the intended user; sudo crontab -u deploy -l; /etc/cron.d/ filesEdited root's crontab while the app runs as www-data
Daemon upsystemctl status cron (Debian/Ubuntu) or crond (RHEL)Minimal container image with no cron installed
Time zonetimedatectl; cat /etc/timezone; optional CRON_TZ=Europe/London line above the job"9am" meant London but the VPS is UTC
PATH / cwdCron's default PATH is tiny (/usr/bin:/bin); no login profilenode, python, npm "not found" — job exits in milliseconds
Absolute pathsUse /usr/bin/node /home/app/run.js or set PATH= on the lineRelative ./script.sh from an unknown cwd
Day OR ruleBoth day-of-month and day-of-week restricted0 0 13 * 5 runs every 13th and every Friday, not only Friday the 13th
Output / mailMAILTO=, redirect >>/var/log/job.log 2>&1Job ran, failed, and the only clue was discarded mail
PermissionsScript executable; readable by that user; SELinux/AppArmor rare but realPermission denied running script
Locked / nologinpasswd -S user; shell in /etc/passwdSome systems skip cron for locked or nologin accounts

Where the logs are

Environment traps

# Bad — relies on interactive PATH
*/5 * * * * node /home/app/job.js

# Better — absolute binary + log
*/5 * * * * /usr/bin/node /home/app/job.js >>/home/app/logs/job.log 2>&1

# Or set PATH on the line / in the crontab header
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
CRON_TZ=Europe/London
0 9 * * 1-5 /home/app/bin/weekday.sh

Cron does not load ~/.bashrc, nvm, pyenv or systemd user environment. If you need those, call a wrapper script that sources them explicitly, or use a systemd timer with Environment= / EnvironmentFile=.

Docker, Kubernetes and CI

Still stuck?

Related

Cron every 5 minutes · cron @reboot · Cron Expression Explainer · Anvil cron explainer API · Permission denied running script · EADDRINUSE

Questions

Why is my cron job not running?

Usually the wrong user's crontab, a PATH that cannot find your binary, a time-zone mismatch (UTC vs local), or an expression that does not mean what you think. Decode it first, then check syslog/journalctl.

How do I see if cron tried to run my job?

On Debian/Ubuntu: grep CRON /var/log/syslog or journalctl -u cron. On RHEL: /var/log/cron. Also redirect your own stdout/stderr to a log file.

Does cron use my .bashrc?

No. Cron has a minimal environment. Use absolute paths, set PATH/SHELL/CRON_TZ in the crontab, or call a wrapper script that sources what you need.

Why did 0 0 13 * 5 run on a Thursday?

When both day-of-month and day-of-week are restricted, classic cron uses OR: it runs on the 13th and on Fridays. The explainer warns about that.

Cron vs systemd timers?

Timers integrate with journald, dependencies and EnvironmentFile. Cron is still fine for simple user jobs; pick one and log deliberately.

How can I get next run times from a script?

GET https://api.oddlathe.com/v1/cron/explain?expr=…&tz=…&n=5 (docs at /docs/cron-explain). No API key.

Published .

Try it

Related guides

Newest guides