Scheduled tasks sharing a due time: only the first 3 fire, the rest are silently dropped and left enabled with a past nextRunAt (Windows, 2.1.217)

Status Closed — not planned
Reported on v2.1.217
Maintainer reply None cached
Activity 1 comment · opened Jul 30, 2026 · closed Jul 30, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

When several one-time scheduled tasks share the same fireAt, only the first three fire. The remainder are silently dropped — they stay enabled: true with nextRunAt frozen at the now-past due time, and are never retried. No error, no notification, no trace anywhere.

This is not a wake/sleep or connectivity failure: the machine was awake, the app was open and actively in use, and three sibling tasks fired normally in the same instant.

Environment

  • Claude Code 2.1.217, Windows desktop app
  • Windows 11 Pro 10.0.26200
  • 6 one-time (fireAt) tasks, all due 2026-07-30T22:05:00.000Z
  • Created by 6 parallel Claude Code sessions pausing at a usage-window reset, each scheduling its own resume

Evidence

Six tasks, identical fireAt. Exactly three fired, ~150 ms apart, then it stopped:

| # | taskId | fired | lastRunAt | enabled after |
|---|---|---|---|---|
| 1 | adr0114-push-pr | ✅ | 22:05:48.334Z | false (auto-disabled, correct) |
| 2 | resume-mefor-adr0076-pr84 | ✅ | 22:05:48.484Z | false (correct) |
| 3 | resume-maturity-posture-pr96 | ✅ | 22:05:48.641Z | false (correct) |
| 4 | resume-vault-salvage-survey | ❌ | absent | true, nextRunAt = 22:05:00.000Z |
| 5 | resume-adr-0154 | ❌ | absent | true, nextRunAt = 22:05:00.000Z |
| 6 | resume-engine-code-defects-pr | ❌ | absent | true, nextRunAt = 22:05:00.000Z |

The split follows creation order exactly. SKILL.md mtimes (epoch): 1785448375, 1785448387, 1785448389 → fired; 1785448392, 1785448401, 1785448416 → dropped. The three oldest ran; the three newest did not. That ordering makes a concurrency cap of 3 with no queue and no retry the most likely mechanism — the overflow is discarded rather than deferred.

Verified still unfired 7+ minutes after the due time, with the app open and responsive. nextRunAt remains in the past and nothing re-evaluates it, so these tasks appear "scheduled" indefinitely while being permanently dead.

Expected

Either (a) all six run, queued behind the cap, or (b) the overflow retains a future nextRunAt and fires when a slot frees. Whichever is chosen, a task that was due and did not run must not be left enabled: true with a past nextRunAt and no record.

Actual

Three run. Three are dropped with no error surface, no notification, and a ledger state that is indistinguishable from "still scheduled."

Why this one is costly

The failure is silent and inverted: the ledger reports a healthy, enabled, scheduled task. The only way to discover it is to notice the work never happened. In this case each dropped task carried a self-contained resume prompt for a paused session — so a dropped fire means paused work is stranded with no signal.

It also concentrates precisely where it hurts: parallel sessions pausing at a shared usage-window reset all schedule for the same moment, so the tasks most likely to collide are exactly the ones created by this workflow. A round number like :05 makes collision the norm, not an edge case.

Reproduction

  1. Create 6 one-time tasks with the same fireAt a few minutes out (separate sessions, or sequentially in one).
  2. Keep the app open and the machine awake.
  3. At the due moment, observe three fire ~150 ms apart.
  4. list_scheduled_tasks: the other three show enabled: true, nextRunAt in the past, no lastRunAt. They never fire.

Related

  • #76961 — local scheduled tasks: silent no-trace failures + missed-run ledger desync. Same class (silent drop, ledger desync) but macOS, ~37 tasks, cron cadences, and attributed to sleep/wake and connection-drop paths. This report is Windows, one-time fireAt, machine awake, and has a sharper signature: a clean 3-fired/3-dropped split by creation order at a single instant, which points at a concurrency cap rather than a wake or transport failure.
  • #55631 — scheduler stops firing until restart.
  • #72710 — one-time fireAt never fires (backing file never persisted). Distinct here: the backing files persisted fine and three siblings fired from the same batch.

Suggested fix

  1. Queue the overflow instead of discarding it — respect the cap, but drain it.
  2. Never leave enabled: true with a nextRunAt in the past; that state is unreachable and reads as healthy.
  3. Surface a dropped/skipped fire (notification or a lastError on the task) so silent loss is impossible.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗