CronHub

Build cron expressions visually — with a live schedule preview.

Cron Job Not Running? 10 Causes and Fixes

Your cron job isn't running, and cron isn't telling you why. The frustrating part is that cron fails silently — no popup, no obvious error, just a task that never happened. The good news: almost every case of a cron job not running comes down to one of ten causes, and each takes under a minute to check.

Run through this checklist first, then read the detailed fixes below.

Quick Diagnostic Checklist

  1. Is the cron daemon running? → systemctl status cron
  2. Did cron try to start your job? → grep CRON /var/log/syslog
  3. Are you using absolute paths for every command and file?
  4. Is the script executable? → ls -l /path/to/script.sh
  5. Are you checking the right user's crontab? → crontab -l vs sudo crontab -l
  6. Does the schedule mean what you think? → verify at crontab.guru
  7. Is output being captured anywhere? → add >> /tmp/job.log 2>&1
  8. Does the command contain an unescaped %?
  9. Does the crontab end with a newline?
  10. Do both day fields conflict? (day-of-month vs day-of-week is an OR)

Nine times out of ten, the answer is in items 1–3. Let's dig into each cause.

First: Determine Whether Cron Started the Job at All

This single distinction cuts your search space in half. Check the cron log:

grep CRON /var/log/syslog | tail -20     # Debian/Ubuntu
sudo grep CRON /var/log/cron | tail -20  # RHEL/CentOS
journalctl -u cron --since "1 hour ago"  # any systemd distro

When Cron Never Launches the Job

The cron daemon isn't running

Rare, but check it first because it explains everything:

systemctl status cron    # Debian/Ubuntu
systemctl status crond   # RHEL/Fedora

If it's dead, sudo systemctl start cron and sudo systemctl enable cron.

You're looking at the wrong crontab

Each user has a separate crontab, and root's is distinct from yours. A job added under sudo crontab -e will not appear in crontab -l. Check both:

crontab -l
sudo crontab -l

Also remember /etc/crontab and /etc/cron.d/* use a six-field format with a username between the schedule and the command. Pasting a five-field user entry there shifts everything by one word and breaks the job.

The schedule doesn't mean what you think

Two classics:

Paste your expression into crontab.guru and read the English translation back.

The crontab file is malformed

A missing final newline can cause the last line to be ignored on some cron implementations, and a syntax error can invalidate an entry. Always edit through crontab -e — it validates on save — rather than editing spool files directly.

When Cron Starts the Job but It Fails

This is the more common scenario: syslog shows the job launched, yet nothing happened. The culprit is almost always cron's stripped-down environment.

PATH and environment differences

Your interactive shell has a rich PATH, aliases, and profile scripts. Cron has almost none of that — typically just /usr/bin:/bin. So python3 script.py works at your prompt and dies in cron.

Fixes, in order of preference:

# 1. Absolute paths everywhere
*/10 * * * * /usr/bin/python3 /home/user/app/task.py

# 2. Or set PATH at the top of the crontab
PATH=/usr/local/bin:/usr/bin:/bin

Find any binary's full path with which python3.

Relative paths inside the script

Cron runs jobs from your home directory. A script that does ./data/input.csv or writes output.log in "the current directory" behaves differently under cron. Use absolute paths inside scripts too, or cd explicitly on the first line.

The script isn't executable

chmod +x /home/user/scripts/job.sh

Or sidestep permissions by invoking the interpreter: /bin/bash /home/user/scripts/job.sh.

The % character

Cron treats an unescaped % as a newline and passes everything after it to the command's stdin. This breaks innocent-looking commands:

# Broken
0 0 * * * /usr/bin/tar czf /backups/site-$(date +%F).tgz /var/www

# Fixed
0 0 * * * /usr/bin/tar czf /backups/site-$(date +\%F).tgz /var/www

Make the Job Tell You What's Wrong

Stop guessing — capture the output. Append redirection to the entry:

*/10 * * * * /home/user/scripts/job.sh >> /tmp/job-debug.log 2>&1

Wait for the next run, then read /tmp/job-debug.log. The actual error — command not found, permission denied, a Python traceback — will be sitting right there. Alternatively, set MAILTO=you@example.com at the top of the crontab if the machine can send mail.

To reproduce cron's environment interactively when debugging:

env -i /bin/sh -c '/home/user/scripts/job.sh'

If it fails there, it fails in cron — and now you can iterate quickly.

Best Practices That Prevent the Next Mystery

Conclusion

When a cron job is not running, split the problem in two with one command: grep CRON /var/log/syslog. If cron never started the job, fix the daemon, the schedule, or the crontab location. If cron started it and it failed, capture the output with >> /tmp/job.log 2>&1 and let the error message do the diagnosis. Absolute paths, output logging, and a syntax check at crontab.guru will resolve the overwhelming majority of cases.

Keep our crontab examples handy for known-good schedules, and consider proper cron monitoring so the next failure alerts you instead of hiding.

Frequently Asked Questions

Why is my cron job not running even though the syntax is correct?

Most likely the environment: cron's PATH is minimal, so commands that work in your shell fail under cron. Use absolute paths for every binary and file, and redirect output to a log to see the real error.

How do I check the cron log?

On Debian/Ubuntu run grep CRON /var/log/syslog; on RHEL-family systems check /var/log/cron; on any systemd distro use journalctl -u cron. These show when jobs start — your own redirection shows whether they succeed.

Why does my script run manually but not in cron?

Because your interactive shell loads a profile, aliases, and a full PATH that cron never sees. Test with env -i /bin/sh -c 'your-command' to simulate cron's bare environment and expose the missing piece.

Does crontab need a newline at the end?

Yes — some cron implementations ignore or reject a final line with no trailing newline. Editing with crontab -e handles this automatically, which is one more reason to avoid editing spool files by hand.

Need the expression itself? Build and test any cron schedule in our free visual generator — with live upcoming-run previews in Unix and Quartz formats.

Related guides

References