Cron Not Running? 7 Reasons Your Scheduled Jobs Fail Silently

It works when you run it manually. Then you check the logs at 3 AM and realize the cron job hasn't executed in days.

This is one of the most common production nightmares I've seen in 20+ years of field engineering. The job looks fine in your head, runs fine in your terminal, but the scheduler ignores it completely. Let me walk you through the seven places I always check first.

1. The PATH Trap

This is the #1 culprit. Cron runs with a minimal PATH:

echo $PATH # Usually: /usr/bin:/bin 

When you run a command manually, your shell might have /usr/local/bin, /opt/bin, or even Python installed in a non-standard location. Cron doesn't.

# This fails if python3 is in /usr/local/bin * * * * * python3 /opt/scripts/cleanup.py >> /var/log/cleanup.log 

Fix: Use absolute paths for everything, or set PATH explicitly in the crontab:

PATH=/usr/local/bin:/usr/bin:/bin * * * * * /usr/local/bin/python3 /opt/scripts/cleanup.py >> /var/log/cleanup.log 

2. Environment Variables Vanish

Your script might rely on environment variables set in .bashrc or .profile. Cron doesn't source these files.

# This breaks if $API_KEY is set in your .bashrc but not in cron * * * * * /opt/scripts/fetch_data.sh 

Fix: Export variables in the crontab itself:

* * * * * export API_KEY="your_key_here" && /opt/scripts/fetch_data.sh 

Or better yet, use a .env file and source it in the script:

#!/bin/bash set -a source /opt/scripts/.env set +a 

3. Working Directory Changes

Cron always runs from the user's home directory ($HOME), not the directory where the script lives. If your script uses relative paths, it will fail silently or write to the wrong place.

# This fails if you're not in /opt/scripts when cron runs * * * * * cd /opt/scripts && ./process_logs.sh 

Fix: Always use absolute paths, or force the directory change at the start of the command:

* * * * * (cd /opt/scripts && ./process_logs.sh) >> /var/log/process.log 2>&1 

4. Output Goes Nowhere (And You Miss It)

By default, cron sends output to the user's email. If mail isn't configured, output is discarded. Your job might be failing every day and you'd never know.

# Silent failure: errors go to nowhere * * * * * /opt/scripts/broken_job.sh 

Fix: Always redirect output to a log file:

* * * * * /opt/scripts/broken_job.sh >> /var/log/cron/job.log 2>&1 

Check the log daily, or set up monitoring to alert on errors:

tail -f /var/log/cron/job.log | grep --line-buffered "ERROR" 

5. Permissions Are Wrong

The cron user might not have permission to read the script, write to the log, or access the resources the script needs.

# Check if the script is executable ls -la /opt/scripts/broken_job.sh # Should show: -rwxr-xr-x 

Fix: Ensure the script is executable and owned by the right user:

chmod +x /opt/scripts/broken_job.sh chown deploy:deploy /opt/scripts/broken_job.sh 

Also check SELinux or AppArmor profiles that might block execution.

6. The System Is Asleep

If your server is a laptop, VM, or cloud instance that can hibernate, cron jobs won't run during downtime. On systemd systems, check if suspend.target or hibernate.target is enabled:

systemctl status systemd-suspend.service systemctl status systemd-hibernate.service 

Fix: Use systemd.path or anacron for systems that aren't always on:

# Anacron runs missed jobs when the system boots sudo apt install anacron 

Or set up a systemd timer that checks system uptime:

# /etc/systemd/system/myjob.timer [Timer] OnBootSec=5min OnUnitActiveSec=24h AccuracySec=1min  [Install] WantedBy=timers.target 

7. Hidden Syntax Errors in the Crontab

A single extra space, a missing newline, or a malformed time field can cause cron to skip the entire line. Common mistakes:

# Wrong: five fields, not six * * * * * * command # Too many fields # Wrong: month/day confusion 0 9 * * 1 command # This runs at 9 AM on Mondays (1=Mon) 0 9 1 * * command # This runs at 9 AM on the 1st of every month # Wrong: missing newline at end of file * * * * * /opt/scripts/final_job.sh # Some cron implementations need a trailing newline 

Fix: Validate your crontab with crontab -l and review each field carefully:

# List current crontab crontab -l # Validate syntax (GNU cron) crontab -e # Use a linter or checker if available 

The Diagnostic Checklist

When a cron job fails silently, run this checklist in order:

# 1. Check if cron is running systemctl status cron # 2. Check the log sudo tail -100 /var/log/syslog | grep CRON # 3. Test the command manually with the same environment sudo -u deploy env -i HOME=/home/deploy SHELL=/bin/bash PATH=/usr/bin:/bin /opt/scripts/broken_job.sh # 4. Check permissions ls -la /opt/scripts/broken_job.sh ls -la /var/log/cron/job.log # 5. Verify the crontab syntax crontab -l | cat -A # Show hidden characters 

The Bottom Line

Cron is powerful but unforgiving. It doesn't send emails by default, it ignores your environment, and it runs from a fixed directory. The seven reasons above cover 90% of the silent failures I've seen in production.

Next time your scheduled job vanishes at 3 AM, check these seven spots before you pull your hair out.

More ops notes and server reliability guides: jiunotes · ops notes