Why Did My Scheduled Job Stop Running?
First establish whether the scheduler tried at all. Everything after that depends on the answer, and the check takes one command.
Everything depends on one question: did the scheduler try to run it? If it tried and the job failed, you have a job problem. If it never tried, you have a scheduler problem, and they share almost no causes.
If there is no attempt logged at the expected times, keep reading. If there are attempts, the job ran and failed quietly, which is covered in cron job failed silently.
System cron: the six usual causes
Confirm the daemon is actually running. It is the first thing to rule out and the one people skip because it feels too obvious.
Check which user you are looking at. Every user has their own crontab, and a job installed under a deploy user is invisible from your own account. Running crontab -l and seeing nothing proves nothing about another user.
A missing trailing newline will disable the last entry. Vixie cron requires the crontab file to end with a newline, and an entry on the final line without one is ignored. It is silent, it looks correct in an editor, and it has wasted a great many hours.
Files in /etc/cron.d have different rules from a user crontab. They need a user field between the schedule and the command, and a filename containing a dot is ignored by run-parts on some distributions. Both fail without any message.
A full disk stops cron from working properly, as does a locked or expired user account. Check both if the jobs stopped for every job at once rather than for one.
Finally, a server rebuild or a container image change is the most common cause of a crontab that was there last month and is not there now. Cron entries applied by hand do not survive infrastructure that is replaced rather than patched.
GitHub Actions
In a public repository, GitHub automatically disables scheduled workflows when no repository activity has occurred in 60 days. The Actions tab shows a banner first, which nobody sees on a repository nobody has committed to.
The second cause is the default branch rule. GitHub only evaluates schedule triggers from the default branch, so a cron added on a feature branch never fires and never reports anything.
Scheduled runs are also queued rather than guaranteed and can be delayed under load, especially at the top of the hour. A job scheduled at minute 0 that consistently appears late is usually being queued, not broken.
AWS Lambda and EventBridge
The function is almost never the problem. The rule that invokes it is.
A rule flipped to DISABLED by an unrelated Terraform or CloudFormation apply produces exactly this symptom, and CloudWatch alarms on the Errors metric stay green because zero invocations means zero errors.
In-process schedulers
node-cron, APScheduler, robfig/cron and Sidekiq schedulers all live inside a process. A deploy, a crash or an out-of-memory kill takes every schedule with it, and none of them backfill runs missed during the gap.
Check the process restart count before checking anything else. A supervisor restarting the application repeatedly means jobs are being interrupted regularly and the evidence has been tidied away each time.
| Platform | Most common cause | One-line check |
|---|---|---|
| System cron | Crontab lost in a rebuild | crontab -l as the owning user |
| /etc/cron.d | Missing user field or a dot in the filename | cat the file, check the fields |
| GitHub Actions | 60-day inactivity, public repos | gh workflow list --all |
| Lambda | EventBridge rule disabled | aws events list-rules |
| In-process | Process restarted or crashed | Supervisor restart count |
| Kubernetes CronJob | suspend: true, or history limits hiding runs | kubectl get cronjob |
Knowing sooner
Every cause above produces the same symptom: nothing. The only general detector is something outside the scheduler expecting a signal on a schedule and alerting when it does not arrive, which is the pattern SensaCat implements and which is explained in what is a dead man's switch.