Developer guide

Cron Not Running? The 5 Most Common Crontab Mistakes

“I added the line to crontab and nothing happens” is the most repeated sentence in cron support threads — and the answer is almost always one of five small things. None of them is the cron daemon. This guide walks each mistake as a symptom, a diagnosis and a fix, so your next job actually fires.

Benjamin Rotshtein

Written by Benjamin Rotshtein

Updated

Why is my cron job not running even though the line looks right?

Five causes cover most cases, in this order: the five fields are in the wrong order, the command relies on a PATH cron never loads, the script lacks the executable bit, it has no shebang, or output goes to /dev/null so errors vanish. Check each one and always log to a real file while debugging.

What is the number one crontab mistake?
Getting the field order wrong — writing hour before minute, or assuming the second field is the day of week. It is always minute hour day-of-month month day-of-week.
Why does my job say “command not found”?
Cron uses a minimal PATH=/usr/bin:/bin and never loads your shell profile. Use absolute paths or export PATH inside the script.
Why can I run my script manually but cron can't?
Three classic causes: the script lacks the executable bit, it has no shebang, or it depends on environment variables that only exist in your interactive shell.

Before you start: pick your editor

crontab -e opens whatever $EDITOR points to — on most distros that is nano. If you prefer vim, add export EDITOR=vim to your shell profile. Whatever the editor, always edit with crontab -e; editing the spool file under /var/spool/cron directly is silently ignored by the daemon.

The 5 mistakes at a glance

MistakeSymptomFix
1. Wrong field orderJob runs at the wrong time or never runsRemember: minute hour day-of-month month day-of-week
2. Missing PATHCommand not found in the logAbsolute paths or a PATH= line in the crontab
3. Script not executableNothing happens, no errorchmod +x script.sh
4. Missing shebangSyntax errors / wrong shell behavior#!/usr/bin/env bash as the first line
5. Output to /dev/nullFailures are invisible>> /var/log/job.log 2>&1 while debugging

Mistake 1: The wrong field order

The order is fixed: minute, hour, day-of-month, month, day-of-week. People swap hour and minute, or assume a weekday in the second position:

# WRONG — runs at minute 9, every hour, every day
9 0 * * * ./job.sh

# RIGHT — 9:00 AM every day
0 9 * * * /home/user/job.sh

Diagnosis: check the times it actually fires with crontab -l and compare against the intended wall-clock. The cron cheat sheet has the field table with the valid ranges for each position.

Mistake 2: Relying on PATH

Interactive shells export a long PATH; cron starts your job with PATH=/usr/bin:/bin and nothing else. A script that runs fine from the terminal fails under cron with command not found. Three fixes, from best to okay:

# 1. Absolute paths to every binary
0 9 * * * /usr/bin/python3 /home/user/job.py

# 2. Or a PATH= line at the top of the crontab
PATH=/usr/local/bin:/usr/bin:/bin
0 9 * * * python3 /home/user/job.py

# 3. Or export PATH inside the script itself
export PATH=/usr/local/bin:$PATH

Mistake 3: The script is not executable

If the crontab line invokes the file directly and the file lacks the execute bit, cron fails silently — no error in your inbox, no entry in the log. Fix:

chmod +x /home/user/job.sh
# verify:
ls -l /home/user/job.sh   # want -rwxr-xr-x

If you prefix the command with an interpreter instead — bash /home/user/job.sh — the bit is not required, because bash reads the file as a script.

Mistake 4: No shebang

Without a first line like #!/usr/bin/env bash, an executable script is interpreted by /bin/sh. Bash-isms such as [[ ]], arrays or source then throw syntax errors that land in /dev/null. Add the shebang as line one and run bash -n job.sh to syntax-check it locally.

Mistake 5: Everything to /dev/null

1>/dev/null 2>&1 is fine for a proven job and terrible for a new one — every error disappears and a broken cron looks identical to a working cron. While debugging, capture output:

0 9 * * * /home/user/job.sh >> /var/log/job.log 2>&1

For a job that must always run, consider systemd timers, which collect logs in journald automatically. And the cron-not-running deep dive covers 9 further causes beyond these 5.

How to verify a fix quickly

Make the job fire within a minute to confirm: temporarily set the schedule to * * * * *, run systemctl status cron (or pgrep cron) to confirm the daemon is up, then inspect the log file. Once it works, restore the real schedule.

Generate a valid expression

Remove the whole class of field-order mistakes by building the expression visually — the Cron Generator emits the correct 5-field string and previews the next runs before you ever touch crontab.

Frequently asked questions

Why is my cron job not running even though the line looks right?

Five causes cover most cases: the 5 fields are in the wrong order, the command relies on a PATH cron does not load, the script lacks the executable bit, the script has no shebang, or output is sent to /dev/null so errors are invisible. Check each in that order and log output to a real file while debugging.

Does cron load my PATH and shell profile?

No. Cron runs commands in a near-empty environment with a default PATH of /usr/bin:/bin and no login shell, so .bashrc and .bash_profile are never sourced. Fix it by exporting PATH inside the script, using absolute paths to every binary, or adding a PATH= line at the top of the crontab.

Do cron scripts need to be executable?

If the crontab line runs the file directly (e.g. /home/user/job.sh), yes — the file needs the execute bit, or cron silently does nothing. Set chmod +x /home/user/job.sh. If you prefix it with bash /home/user/job.sh instead, the executable bit is not required.

What happens if my script has no shebang?

Cron interprets the script with /bin/sh by default. If the script uses Bash-only syntax such as arrays, [[ ]], or source, /bin/sh fails with a syntax error you never see because output went to /dev/null. Add #!/usr/bin/env bash as the first line and chmod +x the file.

Why does my crontab open in nano?

Because nano is the default editor on most distros and crontab -e just launches whatever EDITOR (or VISUAL) points to. Set export EDITOR=vim (or nvim, code) in your shell profile to pick another editor. Editing with crontab -e is required — editing the spool file directly is ignored.

Should I send cron output to /dev/null?

Not while debugging. With 1>/dev/null 2>&1 every error disappears and a silent failure looks identical to a success. Log to a file with >> /var/log/job.log 2>&1 while you verify, and only silence the job once it provably works.

Related guides