What do you do when a Cloudflare Cron Trigger silently stops firing while the schedule API and the handler both look healthy?
The Cloudflare Cron That Stopped Firing and Never Came Back
On 2026-10-23 an every-minute Cloudflare Cron Trigger stopped firing during a Cloudflare incident and never resumed, while the schedule API still listed it. Redeploys, re-registration and a brand-new Worker did nothing. A self- rearming Durable Object alarm fixed it. For must-run jobs, use an alarm plus a dead-job check.
- Cloudflare Workers
- Cron Triggers
- Durable Objects
- D1
- Sentry
Relevant services: Second Brain Audit — €750 · Thrivbe AI
Hypothesis
A small app for planning a cabin trip keeps a Google Sheet and its own database in sync. A Cloudflare Cron Trigger ran the sync every minute. On 2026-10-23 the sync stopped. We assumed a broken deploy or a bad schedule, so the plan was to find the bug in our own code and re-register the trigger.
What we built
- A diagnosis, in order. The schedule API still listed the cron. The
Worker still had a
scheduledhandler. A live log of the Worker showed zero scheduled events. The only signal in the app itself was thelast_oktimestamp of the sync going old with nolast_errornext to it. - Everything we tried on the cron. A trigger redeploy, clearing and
re-setting the schedule, a full redeploy, a changed expression (
*/1), and a fresh cron on a brand-new Worker. None of them fired. Older crons on the same account kept firing, so the account was not the problem. - The cause we could find. Cloudflare's status page lists an incident titled "Delayed, missed, and duplicated Workers Cron Triggers" that started the same day. We have no proof it is the exact cause, only that the timing matches and that re-registering did not help.
- The fix. A separate Worker runs the same guarded sync on a self-rearming Durable Object alarm, every minute. The app's own cron was removed, so the sync can never run twice. Alarms are a different system from Cron Triggers.
- Verification. The first clean sync ran on 2026-10-25 at 20:00 UTC. All 144
sheet-backed items matched the sheet cell by cell, and the tests passed (229).
The
last_oktimestamp moved forward every minute after that.
Learnings
- Healthy-looking config proves nothing. The schedule API and the handler both looked fine while zero events fired. The only honest signal is output: did the job write something recently?
- A stale check cannot live inside the thing it checks. If the staleness alert is run by the same cron, a dead cron also kills the alert. Put the check somewhere that does not share the trigger.
- Re-registering is a trap. We lost time retrying cron variants. When a job writes nothing and logs nothing, check the provider's status page first, then move the job to another trigger type instead of retrying the same one.
- Use an alarm for must-run jobs. A Durable Object alarm that re-arms itself ran on schedule from the first minute. A cron is fine for jobs where a missed run is harmless.
- The outage was also a data event. While the sync was dead, people edited the sheet. Three rows were inserted by hand, which the app's shift guard correctly paused. We repaired the row numbers (55 items) with a recorded restore point before turning the sync back on.
- Check your other crons. The same failure could hit any every-minute Cloudflare cron we run. That is on the follow-up list, not done.
Log
- 2026-10-25: Alarm-based Worker live at about 20:00 UTC, first clean sync verified, change merged the same day.
- 2026-10-23: Cron stops at 11:52 UTC. Redeploy, re-registration, a changed expression and a new Worker all fail to bring it back.
