EUComply

Cron Job Failure Alerts in 2026: How to Know When a Cron Job Fails

By DeskUptime · Updated August 31, 2026 · 7 min read

TL;DR Cron jobs fail silently: exit codes go nowhere unless you catch them. The two reliable patterns are (1) wrap your job so failures trigger an HTTP call, and (2) a dead man's switch — a monitoring service that expects a ping on every run and alerts you when the pings stop. Free tiers from Healthchecks.io, Cronitor, and UptimeRobot cover small setups; a one-time desktop monitor covers URL-based checks without a monthly bill.
Check any site right now — free
Status, response time and SSL certificate expiry in seconds. No sign-up.
Want an alert before it breaks? DeskUptime monitors it for you — $19 once, no subscription.

The problem: cron never tells you it failed

Every server has them: the nightly database backup, the certificate renewal, the report generator, the invoice sync. They're set up once with crontab -e and then forgotten — until the day the disk fills up, a dependency changes its path, or the server reboots and cron doesn't start. The job fails. Nothing breaks visibly. Three weeks later a restore is needed and the newest backup is 24 days old.

Cron itself has no alerting. Output goes to mail if a local MTA is configured (usually it isn't), and exit codes are discarded. So "monitoring cron" means adding something around the job.

Pattern 1: alert on failure (push)

The direct approach: when the job exits non-zero, make an HTTP request to something that can notify you.

# Example: alert via a webhook when the backup fails
0 2 * * * /usr/local/bin/backup.sh || curl -fsS \
  https://your-hook.example.com/alert/backup-failed?host=$(hostname)

This catches hard failures — non-zero exits. It misses two big categories:

Pattern 2: the dead man's switch (pull)

A dead man's switch inverts the logic. You register a unique URL with a monitoring service and append a success ping to your job:

0 2 * * * /usr/local/bin/backup.sh && curl -fsS https://hc-ping.com/<uuid>

The service expects that ping every night at 02:00. If it doesn't arrive — whether the job crashed, hung, or never ran — you get an email, Slack message, or SMS after the grace period you configured. This single pattern covers all three failure modes, which is why it's the standard approach for cron.

Tool comparison

ToolFree tierDead man's switchNotes
Healthchecks.io20 checksYes (core feature)Open source, self-hostable. The default answer for cron.
Cronitor5 monitorsYesPurpose-built for cron, nice CLI. Paid plans from ~$20/mo.
UptimeRobot50 checks, 5-min intervalNo (URL up/down only)Good for websites, wrong shape for jobs.
Better Stack / Site24x7LimitedYesBundled into larger observability suites.
DeskUptime (desktop)Free CLI & appPolls any URL on a schedule$19 one-time. Runs locally; good when you want URL checks without another SaaS subscription.

Which pattern should you use?

  1. Critical jobs (backups, billing): dead man's switch with Healthchecks.io's free tier. It's the only pattern that catches "never ran".
  2. Jobs whose output matters (sync endpoints, generated files): add a URL check that verifies the result — e.g. poll /reports/latest.json and confirm it returns 200 with today's date. A desktop monitor like DeskUptime does this locally on any schedule, with desktop notifications, for a one-time price.
  3. Everything else: route stderr somewhere you actually read, or accept silence knowingly.

Common mistakes

Bottom line

For most teams the answer takes ten minutes: add && curl https://hc-ping.com/<uuid> to critical jobs and let Healthchecks.io watch for missed pings. For checking that the outputs of those jobs stay healthy — URLs, APIs, certificates — pair it with scheduled URL checks. If monthly SaaS fees for simple checks bother you, DeskUptime runs those checks from your own desktop for $19 once instead of $19 every month.