Desktop app scheduled tasks: missed-run catch-up dispatch silently dropped during app startup (no retry); lastRunAt stamped at dispatch; no 529 retry mid-run

Open 💬 0 comments Opened Jul 3, 2026 by albertdelariva

Environment

  • App: Claude desktop app for Windows (MSIX / Microsoft Store), observed on 1.17377.2, still present after update to 1.18286.0
  • Claude Code bundle: 2.1.197
  • OS: Windows 11 Pro 10.0.26200
  • Feature: Local scheduled tasks ("Local routines") — cron-scheduled agent sessions

Summary

I run a daily scheduled task (0 7 * * 1-5) on a laptop that is asleep at 07:00. The scheduler's missed-run catch-up correctly dispatches the task seconds after the app starts at machine wake — but since ~2026-07-02 this dispatch is silently dropped during app startup: no session is ever created, and after exactly 15 minutes the scheduler logs Cleared stale pending dispatch and gives up with no retry and no user-visible error. Because lastRunAt is stamped at dispatch time, the task list shows a plausible "last run" timestamp, so the failure is invisible unless you check the task's actual outputs.

Three distinct defects, all observed in %APPDATA%\Claude\logs\main.log:

Defect 1 — catch-up dispatch dropped during app startup, discarded after 15 min, no retry

The missed-run dispatch fires ~6 s after app launch, while the renderer is still initializing (main_view_dom_ready_ms: 9832; on 02-Jul there was a 16.5 s main-process event-loop stall right after dispatch). The session spawn never completes — no Confirmed task run is ever logged — and a hardcoded 15-minute stale timer then discards the dispatch silently:

2026-07-03 09:48:30 [info] [wake-scheduler] registered claim id=scheduled-tasks
2026-07-03 09:48:36 [info] [CCDScheduledTasks] Spawning new session for scheduled task daily-sweep { cronExpression: '0 7 * * 1-5', fireAt: undefined, lastRunAt: '2026-07-03T07:48:36.463Z', missed: '2026-07-03T05:00:00.000Z' }
   (no "Confirmed task run" ever follows)
2026-07-03 10:03:36 [warn] [CCDScheduledTasks] Cleared stale pending dispatch for: daily-sweep

Identical pattern on 2026-07-02 (dispatch 10:04:26 → Cleared stale pending dispatch 10:19:26, with a [event-loop-stall] main process blocked for 16503ms [likely sleep/wake] at 10:05:05 in between).

This looks like a regression: the identical wake-time catch-up path worked 3-for-3 on 26/29/30-Jun (dispatch → Confirmed task run within 2–11 s each time) and has failed 2-for-2 since the 02-Jul auto-update. From that update onward, the scheduled-tasks service also initializes twice at startup (doubled [CCDScheduledTasks] Reset / Initialized pairs, [warn] [ScheduledTasks] Already initialized) — still the case on 1.18286.0.

By contrast, a second task scheduled at midday — when the app has been running for hours — spawns reliably every time (dispatch → Confirmed task run in under a second). The fragile window is specifically dispatch-during-startup.

Expected: a pending dispatch that fails to spawn should be retried (or re-queued once the app finishes initializing), and if finally abandoned, should surface an error to the user.

Defect 2 — lastRunAt stamped at dispatch, so a lost run looks successful

lastRunAt is written when the dispatch is attempted (visible in the Spawning new session log line itself, which already carries the fresh lastRunAt), not when a session completes — the 02/03-Jul runs that never created a session still show plausible lastRunAt values in list_scheduled_tasks/UI. There is no way to distinguish "ran fine" from "silently dropped" without independently checking the task's side effects.

Expected: either stamp lastRunAt on session completion, or expose a separate last-run status (completed / failed / dropped).

Defect 3 — scheduled session killed by transient 529 is not retried/resumed

On 2026-07-01 the dispatch worked, the session ran ~5 minutes, then died on a transient API Error: Overloaded (rendered as "Service is busy" in the UI) before writing any output. Nothing retries or resumes a scheduled session that dies on a transient API error, so the whole run is lost.

Expected: transient 5xx mid-run in an unattended scheduled session should be retried with backoff (the same event in an interactive session just gets retried by the user; a scheduled session has no user).

Impact

A daily unattended workflow silently produced nothing 3 out of 4 weekdays (01–03 Jul), while the scheduler UI suggested it had run. Unattended reliability is the entire point of scheduled tasks; silent loss + misleading lastRunAt is the worst combination, and forced me to build a second "watchdog" scheduled task whose only job is to detect and re-run lost morning runs.

Repro conditions

  1. Windows laptop, desktop app installed (MSIX), a scheduled task with a weekday cron at a time the machine is asleep.
  2. Machine sleeps through the cron time; open the laptop/app mid-morning.
  3. Watch main.log: Spawning new session for scheduled task … seconds after launch, no Confirmed task run, then Cleared stale pending dispatch +15 min. No session in the sidebar, task outputs absent, lastRunAt freshly stamped.

(Happy to provide fuller log excerpts privately; account/org IDs redacted here.)

View original on GitHub ↗