Why a cron job fails silently — and how to catch it
A cron job fails silently because cron does not alert you when a job fails or when it never runs at all — it just discards the output (or mails it to a local mailbox nobody reads). The two silent-failure classes are a job that runs and errors without anyone seeing the error, and a job that stops running entirely (a removed crontab line, a disabled schedule, a rebooted box). The reliable fix is a dead man's switch: the job reports success to an external monitor, and the monitor alerts you when that report doesn't arrive.
Why do cron jobs fail silently?
- cron discards output by default: unless you redirect stdout/stderr to a file or a monitor, the error a failing job prints goes nowhere you'll see. cron may mail it to the local user's mailbox, which on most servers is never read.
- cron doesn't alert on failure: a non-zero exit produces no notification. Nothing emails, pages, or flags you — the job just didn't work.
- cron can't tell you about a run that never happened: if the crontab entry was removed, the schedule disabled, or the machine was down at the scheduled minute, there is no run and therefore no output at all — the most invisible failure of them all.
- A script that ignores errors: without `set -e`, a script continues past a failed command and can exit 0, actively reporting success while the real work failed.
How do I catch a silent cron failure?
Use a dead man's switch. Instead of trying to catch every possible error inside the job, invert it: the job reports success to an external monitor, and the monitor alerts you when success doesn't arrive on schedule. That single pattern catches both silent classes at once — a job that errors withholds its success ping, and a job that never runs sends nothing at all.
#!/usr/bin/env bash
set -euo pipefail # fail loudly, don't mask errors
/usr/local/bin/nightly.sh # the real work; aborts the script on any error
# Only reached on full success. If the job errors OR never runs, no ping arrives
# and the monitor alerts you that the run missed.
curl -fsS -m 10 --retry 3 "https://ping.cronshield.com/<your-check-id>"How do I make failures visible too, not just misses?
Capture the output so a failure has evidence, and send a failure signal explicitly so you learn about an error the moment it happens rather than at the next expected window:
#!/usr/bin/env bash
set -uo pipefail
if /usr/local/bin/nightly.sh >> /var/log/nightly.log 2>&1; then
curl -fsS -m 10 "https://ping.cronshield.com/<your-check-id>" # success ping
else
curl -fsS -m 10 "https://ping.cronshield.com/<your-check-id>?fail=1" # failure ping — alert now, with the log
fiCatch this failure automatically
The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.
Frequently asked questions
- Why didn't cron email me when my job failed?
- cron only mails output to the job's local user mailbox, and only if a mail transfer agent is configured — on most modern servers it isn't, so the mail goes nowhere. Even when it works, that mailbox is rarely read. cron never sends an external notification on failure by itself.
- How do I know if a cron job stopped running entirely?
- You can't tell from cron — a run that never happens leaves no trace. An external heartbeat monitor is what surfaces it: when the expected success ping doesn't arrive in its window, the monitor alerts you, whether the job errored or the schedule silently stopped.
Primary sources
- man crontab(5) — cron mails command output to the crontab owner; minimal environment — verified 2026-07-04
- man cron(8) — cron behavior and MAILTO handling of job output — verified 2026-07-04