Cron job not running? 10 common causes and how to fix them
Your crontab looks right and the job still never runs. These are the ten causes behind almost every silent cron failure, in the order worth checking them.
You add a line to your crontab, wait for the time to come round, and nothing happens. No error, no email, no log line you can find. Cron fails quietly, which makes it feel mysterious, but the causes are few and they repeat. Work down this list and you will almost certainly find yours.
First, make cron tell you what happened
Before guessing, capture the output. Cron tries to email whatever a job prints to its owner, and on most servers that mail goes nowhere. Send both output streams to a file instead:
*/5 * * * * /home/deploy/sync.sh >> /tmp/sync.log 2>&1
Wait for the next run and read the file. An error message there turns a guessing game into a single fix. It is also worth checking whether cron tried to run the job at all:
grep CRON /var/log/syslog # Debian and Ubuntu
journalctl -u cron # Debian and Ubuntu with systemd
journalctl -u crond # Red Hat, Fedora, Rocky
If the log shows your command at the right time, cron did its part and the problem is inside the job. If there is no entry, the problem is the schedule or cron itself.
1. The cron service is not running
On a fresh server, a minimal image or a container, cron may not be installed or started.
Check with systemctl status cron (the service is called crond on Red Hat based
systems) and start it with sudo systemctl enable --now cron. Docker containers
usually run a single process and have no cron at all unless you add it.
2. The schedule is not what you think
Paste the expression into the cron expression generator
and read the plain English version and the next run times. The classic mistakes are
* 5 * * *, which runs every minute of the five o’clock hour instead of once, and
setting both day fields, which makes cron run when either one matches rather than both.
3. The server is on a different time zone
Cron follows the machine’s clock, and servers are usually set to UTC. A job written for
9:00 in New York runs at 9:00 UTC, which is 4:00 or 5:00 in the morning there depending
on the season. Check the clock with date or timedatectl. The
guide to cron time zones covers the fixes.
4. The command is not on cron’s PATH
This is the most common cause of all. Cron runs jobs with a minimal environment, and its
PATH is usually just /usr/bin:/bin. A command that works in your terminal because it
lives in /usr/local/bin, or comes from a Node, Python or Ruby version manager, is simply
not found. Use full paths in the crontab (which node tells you where it is), or set
PATH at the top of the crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
5. Environment variables are missing
Cron does not read your .bashrc or .profile, so API keys, database URLs and anything
else you export in your shell are not there. Set them in the crontab, load them inside
the script, or point the script at an env file using its full path.
6. The script relies on its working directory
Cron starts jobs in the user’s home directory, not in the folder the script lives in. A
script that opens config.yml or writes to ./data works when you run it from its own
folder and fails under cron. Change directory first, as in cd /srv/app && ./run.sh, or
use absolute paths inside the script.
7. The script is not executable, or has the wrong line endings
If the crontab calls a script directly, the script needs execute permission and a first
line such as #!/bin/bash. Run chmod +x script.sh, or call it through its interpreter:
/bin/bash /path/to/script.sh. A script saved on Windows can also carry Windows line
endings, which produce a “bad interpreter” error; dos2unix fixes that. The
chmod calculator explains what each permission allows.
8. A percent sign in the command
In a crontab, % is special: cron turns it into a newline and feeds everything after it
to the command as input. A command such as date +%Y-%m-%d is cut short and fails. Escape
each one with a backslash, date +\%Y-\%m-\%d, or move the command into a script.
9. The last line has no newline
Cron expects every line of a crontab, including the last one, to end with a newline.
Depending on the version, a missing one means the last job is ignored or the whole file
is rejected. If only the final job never runs, open the crontab with crontab -e, go to
the end of the last line and press Enter before saving.
10. You edited the wrong crontab
Every user has a crontab of their own, and root’s is separate from yours. A job added
with sudo crontab -e runs as root, while crontab -e runs as you, with different
permissions and a different home directory. The system file /etc/crontab and the files
in /etc/cron.d/ also need an extra field naming the user, between the schedule and the
command; without it the line is rejected. List what is really installed with crontab -l,
and sudo crontab -l for root.
Jobs that should run after a reboot
If a job needs to run once when the machine starts, cron has a shortcut for it:
@reboot /path/to/script.sh. It fires when the cron service starts, which can be before
the network or a database is ready, so a script that depends on them should wait or
retry. On systemd machines, a service unit with proper dependencies is often the more
reliable choice.
The short version
When a job misbehaves, check in this order: capture the output, confirm cron logged the attempt, check the schedule and the server’s clock, then use full paths and set the working directory. Most problems are gone by the fourth step.