You wrote a script. It works when you run it manually. You added it to crontab. It does not run. Welcome to one of the most common and most frustrating debugging experiences in system administration.
Nine times out of ten, the problem is not the cron expression. It is the environment.
The environment trap
When you run a command in your terminal, it inherits your shell environment: PATH, HOME, environment variables, shell configuration. When cron runs a command, it uses a minimal environment with almost nothing set.
Your script works manually because it finds python3 at /usr/local/bin/python3, which is in your PATH. Cron's default PATH is typically just /usr/bin:/bin. So cron cannot find python3 and the job fails silently.
The fix: use absolute paths for everything in cron jobs.
# Wrong
*/5 * * * * python3 /home/user/scripts/cleanup.py
# Right
*/5 * * * * /usr/local/bin/python3 /home/user/scripts/cleanup.py
Or set PATH explicitly in your crontab:
PATH=/usr/local/bin:/usr/bin:/bin
*/5 * * * * python3 /home/user/scripts/cleanup.py
Silent failures
By default, cron sends output (both stdout and stderr) to the system's mail for the user. If you do not have local mail configured (most modern systems do not), the output vanishes. Your job fails, no error is logged, and you have no idea why.
Always redirect output to a log file:
*/5 * * * * /usr/local/bin/python3 /home/user/scripts/cleanup.py >> /var/log/cleanup.log 2>&1
The 2>&1 redirects stderr to the same file as stdout. Without it, errors go to mail (or nowhere) while normal output goes to your log file.
Common failure modes
Permission denied: The script is not executable, or cron does not have permission to access a file. chmod +x the script and ensure the cron user can read all referenced files.
Working directory: Cron jobs start in the user's home directory, not the directory where the script lives. If your script references relative paths like ./data/input.csv, it is looking in the home directory. Use absolute paths or cd at the start of the command.
*/5 * * * * cd /home/user/project && ./scripts/cleanup.sh
Missing environment variables: If your script relies on environment variables (API keys, database URLs), they are not available in cron. Either set them in the crontab file or source a file that defines them:
*/5 * * * * . /home/user/.env && /home/user/scripts/deploy.sh
Editor differences: crontab -e uses the system's default editor. If EDITOR is not set, you might get vi when you expected nano. Not a failure mode per se, but it causes people to accidentally corrupt their crontab.
Validating your expression
Before waiting to see if your cron job runs at the scheduled time, validate the expression. crontab -l shows your current crontab. But it does not tell you when the next execution will be.
The fastest validation is to set a test job that runs every minute and writes to a file:
* * * * * date >> /tmp/cron-test.txt
If this file is not being written to, cron itself is not running (check with systemctl status cron or service cron status).
For validating complex expressions, you need a tool that parses the expression and shows you the next execution times. I built a crontab guru tool that explains cron expressions in plain English and shows the next scheduled runs, so you can verify your expression is correct before deploying.
I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.
Top comments (0)