Scheduled tasks: only the first 3 of 6 simultaneously-due one-time tasks fire; the rest are silently dropped and left permanently armed

Status Closed — not planned
Maintainer reply None cached
Activity 2 comments · opened Jul 30, 2026 · closed Jul 30, 2026

Summary

When several one-time scheduled tasks come due at the same instant, only the first three fire. The rest are silently skipped, and they are left in a state they can never recover from: enabled: true with a nextRunAt in the past. No error is surfaced anywhere — not to the sessions that created them, not in the Scheduled sidebar.

The failure is silent, which is the worst part. Each session reports "trigger armed" to its user and stops. The user believes the work will resume. It never does, and nothing says so.

Evidence

Six one-time tasks were created by six parallel Claude Code sessions, all with the identical fireAt of 2026-07-30T22:05:00.000Z. list_scheduled_tasks afterwards:

| # | taskId | lastRunAt | enabled | nextRunAt |
|---|---|---|---|---|
| 1 | adr0114-push-pr | 2026-07-30T22:05:48.334Z | false | — |
| 2 | resume-mefor-adr0076-pr84 | 2026-07-30T22:05:48.484Z | false | — |
| 3 | resume-maturity-posture-pr96 | 2026-07-30T22:05:48.641Z | false | — |
| 4 | resume-vault-salvage-survey | never ran | true | 2026-07-30T22:05:00.000Z |
| 5 | resume-adr-0154 | never ran | true | 2026-07-30T22:05:00.000Z |
| 6 | resume-engine-code-defects-pr | never ran | true | 2026-07-30T22:05:00.000Z |

Observations:

  • The three that fired did so within a 307 ms window, then dispatch stopped.
  • The split is a contiguous prefix / contiguous suffix by creation order — the three oldest fired, the three newest did not. That is consistent with the dispatcher iterating due tasks in order and stopping after three, rather than with a random drop.
  • The three that fired correctly auto-disabled (enabled: false). Expected behaviour for a one-time task.
  • The three that did not fire remain enabled: true with nextRunAt in the past. Checked again at 2026-07-30T22:11:48Z — 6m48s after the due time — still unfired, still armed. A one-time task whose fireAt has passed appears never to be re-evaluated, so this state is terminal.
  • The app was open the entire time. The three successful runs at 22:05:48Z prove it, and the session observing this was live and interactive throughout. This is not the documented "app was closed, runs on next launch" path.
  • jitterSeconds: 0 on all six, yet dispatch happened ~48 s after the nominal fire time.

Expected

All six fire, or the ones that cannot fire immediately are queued and dispatched as capacity frees, or at minimum the skipped ones surface an error and are retried on the next tick.

Actual

Three run. Three are dropped with no error, no retry, and no recoverable state.

Why this is not an exotic edge case

The trigger here is a completely ordinary workflow: a usage window is about to reset, several parallel Claude Code sessions are told to stop and resume afterwards, and each independently schedules a one-time resume for just after the reset. The reset time is shared, so the pileup is structural — every session picks roughly the same minute because they are all reacting to the same external deadline. Anyone running parallel sessions against a usage limit will hit this.

Worth noting that CronCreate's own documentation warns about exactly this class of collision ("every user who asks for 9am gets 0 9... pick a minute that is NOT 0 or 30"). The same herd problem applies here, but with a deadline-driven fire time there is no freedom to jitter it away — the tasks genuinely need to run just after the reset.

Suggested fixes, roughly in order of value

  1. Never silently drop a due task. If a concurrency cap exists, queue the overflow and dispatch as slots free.
  2. Make past-due one-time tasks recoverable. A task with enabled: true and fireAt in the past should fire on the next tick rather than sit forever.
  3. Surface the failure. The creating session subscribes via notifyOnCompletion (default true) — a skipped task should notify too, not just a completed one.
  4. Spread simultaneous fires automatically rather than dropping them, e.g. a few seconds of dispatch jitter per task when many share a fireAt.

Environment

  • Claude Code desktop app, Windows 11 Pro 10.0.26200
  • Timezone: Central (UTC−05:00 at the time; Get-TimeZone reports Central Standard Time, base UTC−06:00, DST active)
  • Six sessions running in parallel across two repos, in git worktrees
  • Tasks created via the scheduled-tasks MCP (create_scheduled_task, one-time fireAt form)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗