Cron job not running: find out why, and know the next time it fails
When a cron job is not running, first check whether cron started it at all: the cron log shows every job it launches. If cron ran it and nothing happened, the job failed in cron’s bare environment, usually because of a missing PATH, a relative path, a script that is not executable or a % sign cron treats as a newline. Redirect the job’s output to a file and the error is there. Cron only mails a job’s output, which on most servers goes nowhere, so a job that matters needs an alert when it fails or stops running.
Did cron start the job?
systemctl status cron # Debian and Ubuntu; crond on Fedora and RHEL
grep CRON /var/log/syslog | tail -20 # Ubuntu, and Debian with rsyslog
grep CROND /var/log/cron | tail -20 # RHEL and its rebuilds
journalctl -u cron --since "1 hour ago" # any systemd system (crond on RHEL and Fedora)
crontab -l # the jobs of the user you are logged in asA CMD (...) line at the expected minute means cron ran it and the problem is the job. No line means cron never tried: the job is in another user’s crontab, the schedule is not what you think, or cron itself is not running.
The usual causes
| Cause | Fix |
|---|---|
| PATH is only /usr/bin:/bin | Use full paths (/usr/local/bin/node), or set PATH= at the top of the crontab |
| Relative paths and the working directory | Cron starts in the user’s home directory; cd /srv/app && first |
| Script not executable, or no shebang | chmod +x and a #!/bin/bash first line, or call the interpreter |
| A % sign in the command | Cron turns % into a newline; write \%, as in date +\%F |
| Wrong crontab | sudo crontab -e is root’s; files in /etc/cron.d need a user field and a file name without dots |
| Environment variables missing | Cron does not read .bashrc or .profile; source an env file in the job |
| No newline at the end of the crontab | Cron ignores a last line without one |
| Server timezone | Cron uses the server’s timezone; check it with timedatectl and restart cron after changing it |
See the error
Cron mails a job’s output to the user, which on most servers goes nowhere. Send it to a file instead:
*/5 * * * * /srv/app/sync.sh >> /var/log/sync.log 2>&1To reproduce cron’s environment by hand, run the command with an almost empty environment: env -i HOME=$HOME PATH=/usr/bin:/bin /bin/sh -c '/srv/app/sync.sh'. If it fails there, it fails in cron.
In containers and on platforms
Inside a Docker container nothing starts the cron daemon unless the image does, so a crontab in a container usually never runs. Run the job from the host’s cron with docker exec, or use your platform’s scheduler: Coolify and Dokploy scheduled tasks, Render and Northflank cron jobs, DigitalOcean App Platform scheduled jobs, Cloudflare Cron Triggers or Vercel cron jobs.
A scheduled job that crashes on start in a container can also show up as a restart loop; see why a container keeps restarting.