CronDrive
Guides

Why your cron job isn't running

Updated 16 October 2026

When a cron job isn’t running, or a crontab line isn’t executing, it isn’t always clear where to look for the error. Go through these checks in order: first whether cron tried to run the job, then why the command failed.

1. Is the cron service running?

systemctl status cron     # Debian, Ubuntu
systemctl status crond    # RHEL, Fedora, Rocky, AlmaLinux

If it’s stopped, start it and enable it at boot:

sudo systemctl enable --now cron

A Docker container usually has no cron running unless its image starts it. Check that the process is there with ps aux | grep cron, and see how to run cron jobs in a Docker container.

2. Did cron start the job?

Cron logs each command it starts. Look for your job around the time it should have run (more in where to find cron logs):

grep CRON /var/log/syslog                # Debian, Ubuntu
sudo journalctl -u cron --since today    # Debian, Ubuntu with systemd
sudo journalctl -u crond --since today   # RHEL, Fedora
sudo tail -n 50 /var/log/cron            # RHEL, CentOS
  • The command is in the log: cron ran it, and the problem is in the command. Skip to step 4.
  • It isn’t there: check the schedule and the crontab, in step 3. Also make sure you are reading the right log, since it depends on the distribution.

3. Is the schedule what you think?

  • Test the expression. Paste it in the cron tester and check its next runs. A common surprise: when both the day of the month and the day of the week are set, cron runs on either. 0 0 13 * 5 runs on every 13th and every Friday. The rest of the syntax is in the crontab format.

  • Check the server’s time zone. Cron uses the time zone of the server, which may not be yours: timedatectl | grep "Time zone". Some implementations, like cronie, also accept CRON_TZ= in the crontab. After changing the server’s time zone, restart cron. More in cron and time zones.

  • Check whose crontab it is. crontab -l shows yours, and sudo crontab -l shows root’s. The lines in /etc/crontab and /etc/cron.d/ have an extra field with the user, before the command:

    0 3 * * * root /usr/local/bin/backup.sh
  • Name the files in /etc/cron.d/ without dots. On Debian and Ubuntu, cron ignores a file like backup.cron: name it backup.

  • End the crontab with a newline. Cron may ignore a last line without one. crontab -e usually adds it, but a file you copied may not have it.

4. Does the command work in cron’s environment?

Cron doesn’t read your shell profile, so the command runs in a more limited environment than your terminal’s. These are the most common differences:

  • PATH is short, often just /usr/bin:/bin. Commands in /usr/local/bin, or installed with nvm, rbenv or pyenv, aren’t found. Use absolute paths, like /usr/local/bin/node, or set PATH at the top of the crontab:

    PATH=/usr/local/bin:/usr/bin:/bin
  • The shell is /bin/sh, not bash, so source, [[ ]] or arrays fail. Run the script with bash (/bin/bash /path/to/job.sh) or set SHELL=/bin/bash in the crontab.

  • % means a new line in a crontab line, so date +%F breaks the command. Escape it: date +\%F.

  • The working directory is the home directory, so relative paths may point to the wrong directory. Use absolute paths, or cd /path/to/app && ....

  • The variables of .bashrc or .profile aren’t there: API keys, DATABASE_URL, JAVA_HOME. Set them in the crontab or load them in the script.

To try the command almost as cron runs it:

env -i HOME="$HOME" PATH=/usr/bin:/bin /bin/sh -c 'cd ~ && /path/to/job.sh'

More ways to try it, with the exact environment of your cron, in how to run a cron job manually.

5. Can cron run the script?

  • It must be executable, with chmod +x /path/to/job.sh and a first line like #!/bin/bash.
  • The crontab’s user needs access to what the script uses: files, directories, sockets.
  • Line endings from Windows (\r\n) make it fail with /bin/bash^M: bad interpreter. Fix them with sed -i 's/\r$//' /path/to/job.sh.

6. Read the error

Cron emails the output of each command to the crontab’s user, or to MAILTO. If the server isn’t set up to send email, you won’t get that output. Keep it in a file instead:

0 3 * * * /path/to/job.sh >> "$HOME/job.log" 2>&1

Wait for the next run, or change the schedule to run it in a couple of minutes, and look for the error message in that log. If all you have is an exit code, see what it means in cron job exit codes.

Know sooner the next time

These checks help you find the cause once you have noticed the problem. To know sooner, set up alerts for when the job doesn’t start, takes too long or ends with an error.

CronDrive emails you, or posts to Slack, when a job with this schedule fails, or doesn't start or finish on time. Free for up to 15 jobs.

What you'd see with this schedule

An example with the last runs of this schedule and made-up results: one failed and one didn't run.

Times in UTC.

Due
Thu 5 Nov, 03:00 On time Started 03:00, finished 03:13, took 13 min.
Wed 4 Nov, 03:00 Didn't run Alerts sent at 03:05 and 03:30.
Tue 3 Nov, 03:00 On time Started 03:00, finished 03:14, took 14 min.
Mon 2 Nov, 03:00 Failed with code 1 Alert sent at 03:04. Started 03:00, finished 03:04, took 4 min.
Sun 1 Nov, 03:00 On time Started 03:00, finished 03:13, took 13 min.
Sat 31 Oct, 03:00 On time Started 03:00, finished 03:14, took 14 min.

The alert of the failed run

Email from CronDrive, Mon 2 Nov, 03:04

Failed (exit code 1): "Your job"

The job "Your job" failed with exit code 1.

If you connect Slack, the same message goes to your channel.

The change in your crontab

0 3 * * * curl -fsS -m 10 https://job.crondrive.com/uG2Exw/start/$$; /path/to/job.sh; curl -fsS -m 10 https://job.crondrive.com/uG2Exw/end/$?/$$

Two calls around your command, in the same line. Your job's line comes with its own token.

Monitor this schedule