Cron job fails with "command not found" — the PATH trap

You test a script in your shell, it works perfectly, you add it to crontab — and it silently never does its job. If you dig into the logs you find something like backup.sh: line 4: aws: command not found or pg_dump: command not found. The script was fine; cron's environment is not your environment.

Why it happens

Cron runs jobs with a deliberately minimal environment. In particular PATH is usually just /usr/bin:/bin — not the rich PATH your login shell builds from .bashrc, .profile, nvm, pyenv, Homebrew, or /usr/local/bin. So binaries that live outside /usr/bin and /binaws, docker, node, python3 from a venv, anything under /usr/local/bin — simply aren't found. Same reason your HOME-relative configs and shell functions aren't loaded.

The fixes

PATH=/usr/local/bin:/usr/bin:/bin:/home/deploy/.local/bin 0 3 * * * /home/deploy/backup.sh

The real danger: it fails silently

The "command not found" line lands in cron's mail spool or syslog — somewhere nobody watches. The job exits non-zero, does no work, and you find out days later that no backup has run. Exit codes and log-scraping don't help here because you're not reading those logs. What you need is to be told when the job stops succeeding.

Know the moment it breaks

Put a heartbeat ping at the very end of the job, chained so it only fires on success:

0 3 * * * /home/deploy/backup.sh && curl -fsS https://cronping.cronping-oren.workers.dev/ping/<your-check-id>

If a command not found aborts the script, the && short-circuits, the ping never fires, and Cronping emails you that the job went quiet — the first time it skips, not a week later. Add a /fail ping to go DOWN the instant a step errors:

/home/deploy/backup.sh && curl -fsS https://cronping.cronping-oren.workers.dev/ping/<id> || curl -fsS https://cronping.cronping-oren.workers.dev/ping/<id>/fail

Cronping does this free: 20 checks, 1-minute resolution, email + Slack/Discord alerts, no credit card. Create a check and get a ping URL in about ten seconds.

Try it now

Get a ping URL in about ten seconds — no account, no email needed. Add an email later for alerts.

Not sure what it looks like? Watch a 15-second live demo of a check tripping and the alert landing.

Related guides

How to monitor a cron job and get alerted when it fails

A genuinely free healthchecks.io-style cron monitor

Monitor a scheduled GitHub Actions workflow

How to monitor a systemd timer and know when it stops

← All guides