You’ve added your cron job, the syntax looks right, but nothing happens. No output, no errors, just silence. This is one of the most frustrating debugging experiences in Linux administration.

Here’s how to systematically find and fix the problem.

Check If Cron Is Actually Running

First, verify the cron daemon is running:

1
2
3
4
5
6
7
# systemd systems (Ubuntu 16.04+, CentOS 7+, Debian 8+)
systemctl status cron
# or on some systems
systemctl status crond

# Older init systems
service cron status

If cron isn’t running, start it:

1
2
sudo systemctl start cron
sudo systemctl enable cron

Verify Your Crontab Entry Exists

Check that your job is actually in the crontab:

1
2
3
4
5
6
7
8
9
# View current user's crontab
crontab -l

# View root's crontab (if that's where your job should be)
sudo crontab -l

# View system-wide cron jobs
ls -la /etc/cron.d/
cat /etc/crontab

A common mistake: editing /etc/crontab directly instead of using crontab -e, or vice versa. They have different formats—/etc/crontab requires a username field:

1
2
3
4
5
# /etc/crontab format (note the username)
* * * * * root /path/to/script.sh

# User crontab format (no username)
* * * * * /path/to/script.sh

The PATH Problem

This is the #1 reason cron jobs fail. Cron runs with a minimal PATH, typically just /usr/bin:/bin. Commands that work in your shell won’t work in cron.

Bad:

1
* * * * * python3 /home/user/script.py

Good:

1
* * * * * /usr/bin/python3 /home/user/script.py

Find the full path to any command with which:

1
2
3
4
5
which python3
# /usr/bin/python3

which node
# /usr/local/bin/node

Alternatively, set PATH at the top of your crontab:

1
2
3
PATH=/usr/local/bin:/usr/bin:/bin

* * * * * python3 /home/user/script.py

Environment Variables Are Missing

Cron doesn’t load your .bashrc, .profile, or .bash_profile. Environment variables you rely on won’t exist.

Option 1: Source your profile in the cron command:

1
* * * * * source /home/user/.bashrc && /home/user/script.sh

Option 2: Define variables in the crontab:

1
2
3
4
DATABASE_URL=postgres://localhost/mydb
API_KEY=secret123

* * * * * /home/user/script.sh

Option 3: Use a wrapper script that sets up the environment:

1
2
3
4
5
#!/bin/bash
# /home/user/run-with-env.sh
export PATH=/usr/local/bin:/usr/bin:/bin
export DATABASE_URL=postgres://localhost/mydb
exec /home/user/actual-script.sh

Permission Issues

Your script must be executable:

1
chmod +x /home/user/script.sh

Check the shebang line is correct:

1
2
#!/bin/bash
# NOT #!/bin/sh if you're using bash features

If writing to files, ensure the cron user has write permission to the destination:

1
2
# This will fail if /var/log/myapp/ doesn't exist or isn't writable
* * * * * /home/user/script.sh >> /var/log/myapp/output.log 2>&1

Capture Output to Debug

Cron discards output by default. Redirect it to see what’s happening:

1
* * * * * /home/user/script.sh >> /tmp/cron-debug.log 2>&1

The 2>&1 captures both stdout and stderr. Check the log after the job should have run:

1
cat /tmp/cron-debug.log

Also check the system mail—cron sends output there by default:

1
2
3
cat /var/mail/$USER
# or
mail

Check System Logs

Cron logs when jobs run (but not their output):

1
2
3
4
5
6
7
8
# Debian/Ubuntu
grep CRON /var/log/syslog

# CentOS/RHEL
grep CRON /var/log/cron

# systemd journal
journalctl -u cron --since "1 hour ago"

You should see entries like:

Mar1410:00:01serverCRON[12345]:(user)CMD/home/user/script.sh)

If you don’t see your job listed, it’s not being triggered—recheck your timing syntax.

Timing Syntax Mistakes

Use crontab.guru to verify your timing. Common mistakes:

1
2
3
4
5
6
7
8
# Runs at minute 5 of every hour, not every 5 minutes
5 * * * * /script.sh

# Every 5 minutes (correct)
*/5 * * * * /script.sh

# This runs at 2:30 AM, not "every 2 hours and 30 minutes"
30 2 * * * /script.sh

Working Directory Assumptions

Scripts often assume they’re running from a specific directory. Cron runs from the user’s home directory. Use absolute paths or cd first:

1
* * * * * cd /home/user/project && ./script.sh

Or in your script:

1
2
3
#!/bin/bash
cd "$(dirname "$0")"
# Now you're in the script's directory

Quick Diagnostic Checklist

Run through this list when your cron job isn’t working:

  1. Is crond running? systemctl status cron
  2. Is the job in crontab? crontab -l
  3. Using full paths? which command to find them
  4. Script executable? chmod +x script.sh
  5. Capturing output? Add >> /tmp/debug.log 2>&1
  6. Check cron logs for execution evidence
  7. Check mail for error output
  8. Test the command manually with the same user cron uses

Nine times out of ten, it’s the PATH or a missing environment variable. When in doubt, use absolute paths for everything and explicitly set any environment your script needs.