Cron failures are boringly consistent: PATH differences, silent script errors, or the crontab you think is installed isn't.
cron runs with /usr/bin:/bin. Anything installed elsewhere (rake, docker, npx) is 'command not found' — mailed to a mailbox nobody reads.
Env vars, virtualenv activation, or relative paths that assume a login shell.
Installed in the user crontab but needs root, or edited the file without crontab -l ever picking it up.
crontab -l; sudo crontab -l
17 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
grep CRON /var/log/syslog | tail
*/5 * * * * /bin/printenv > /tmp/cron-env.txt
For anything with dependencies, a systemd timer with an explicit Environment and WorkingDirectory beats cron — you also get journalctl logs for free.
Cron runs with a minimal environment: PATH, HOME, and shell differ from your interactive session. Absolute paths for binaries and files, plus a PATH line in the crontab, fix the classic variant.
Redirect output to a file (>> /tmp/job.log 2>&1) and check the system log (grep CRON /var/log/syslog). Silent cron jobs are almost never silent — the output just goes nowhere.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.