# Fix uncaught exception in scheduled handler, cron not firing

## TL;DR

Wrap the entire `scheduled()` body in try/catch and log the error, because an uncaught exception in a cron trigger looks exactly like a cron that never fired. Then verify the cron pattern is registered under `[triggers] crons` in wrangler.toml and watch `wrangler tail` during the scheduled minute to confirm it fires.

## Verbatim error

```text
workerd: uncaught exception in scheduled handler, cron not firing
```

## Steps

1. Open wrangler.toml and confirm a `[triggers]` section with your schedule, e.g. `crons = ["*/5 * * * *"]`. Expected: the pattern parses as a valid cron expression.
2. Run `npx wrangler tail` in a separate terminal. Expected: tail connects and starts streaming logs.
3. Wrap the scheduled handler: `try { ...your work... } catch (e) { console.error("cron failed", e); }`. Expected: the worker deploys cleanly.
4. Wait for the next scheduled minute and watch tail. Expected: you see the trigger fire and either your success logs or the caught error.
5. If nothing appears, check the worker's triggers tab in the dashboard. Expected: the cron shows as an active trigger on the deployed worker.
6. Test the same code path with a direct fetch to a debug route. Expected: the shared logic works, which isolates the problem to the trigger registration.

## Use this when

- A Worker cron never seems to run
- The scheduled handler throws an uncaught exception
- Cron events fire but produce no visible effect

## Not for this skill when

- The cron fires but the business logic is wrong (debug the handler code itself)
- You need sub-minute scheduling (not supported; use a different mechanism)
- You want one-shot future wakeups (use a Durable Object alarm instead)

## Variant phrasings

- cloudflare workers cron trigger not working
- scheduled event not firing workers
- crons = [] ignored wrangler.toml
- worker scheduled handler never called

## Why it happens

Cron events have no HTTP response, so failures are invisible unless you watch tail. An uncaught throw inside `scheduled()` gets logged server-side but never surfaces to you, so the cron looks dead. The other classic cause is a stale deploy: the pattern was added to the config but never deployed, so nothing is registered.

## Edge cases

- Cron triggers only fire on the deployed worker, never in `wrangler dev`; trigger the logic manually when developing locally.
- Minimum granularity is one minute; tighter schedules are silently treated as one minute.
- Long-running crons can overlap with the next tick; make the handler idempotent.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_LPKWWonsou0KXJOVEdr78g
