[BUG] Local scheduled task silently collects nothing on workspace switch, and the dead run reports `succeeded`
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
Environment
- Claude desktop app
1.52386.3, CLI2.1.266, macOS (Darwin 25.6.0) - Local scheduled tasks (
~/.claude/scheduled-tasks/), not cloud Routines
Related but distinct: #92910 is cloud Routines stuck in PENDING. This one is the local desktop scheduler, and the run reports succeeded.
What's wrong
A local cron scheduled task silently collected nothing on 2 of 3 firings over three days. Both losses report succeeded and one of them leaves no session record at all, so run history cannot be used to tell whether a scheduled task did its work.
There are three separate defects here that compound. I have the main-process logs for all of it.
---
1. The scheduler only evaluates the currently active workspace
Each org/workspace has its own scheduled-tasks.json and its own scheduler instance. A cron task whose workspace is not the active one does not fire at its scheduled time — it fires whenever you next switch into that workspace.
My task is 0 9 * * * (09:00 local). Across three days it never once fired at 09:00:
| due | actually dispatched | delay |
|---|---|---|
| 09-15 09:00 | 09:25:48 | +26m |
| 09-16 09:00 | 10:47:50 | +1h48m |
| 09-17 09:00 | 09:41:41 | +42m |
Every one of those is the moment I switched workspaces, confirmed by a Reset → Initialized pair for that org immediately before. On 09-16 and 09-17 the app had been running all night in the other workspace, and the 09:00 slot passed unfired.
mcp__scheduled-tasks__list_scheduled_tasks is also scoped to the active workspace, so it does not show all of a user's scheduled tasks — which made this hard to see.
2. That switch is exactly when dispatches get lost
The missed-run check runs immediately on Initialized, which happens on every workspace switch — while the app is tearing down every shell PTY and reloading sessions. Both lost runs show Reset → Initialized → Spawning new session within the same second:
09-15 09:25:48 [info] [CCDScheduledTasks] Initialized { accountId: '<account>', orgId: '<orgA>' }
09-15 09:25:48 [info] [CCDScheduledTasks] Spawning new session for scheduled task <task>
{ cronExpression: '0 9 * * *', lastRunAt: undefined, missed: '2026-09-15T14:00:00.000Z' }
09-15 09:25:48 [info] [CCDScheduledTasks] Dispatch acknowledged by renderer: <task>
…and then nothing. No Confirmed task run, no session record, no transcript. The run is simply gone.
The next day it happened again, this time with the 5s ack timeout visible:
09-16 10:47:50 [info] [CCDScheduledTasks] Initialized { accountId: '<account>', orgId: '<orgA>' }
09-16 10:47:50 [info] [CCDScheduledTasks] Spawning new session for scheduled task <task>
09-16 10:47:55 [warn] [CCDScheduledTasks] Dispatch not acknowledged by renderer within 5s;
slot left unconsumed, will retry: <task>
09-16 10:47:55 [info] [CCDScheduledTasks] Spawning new session for scheduled task <task>
09-16 10:47:55 [info] [CCDScheduledTasks] Dispatch acknowledged by renderer: <task>
09-16 10:47:56 [info] [CCDScheduledTasks] Confirmed task run for: <task>
09-16 10:47:58 [info] [ScheduledTasks] Reset
09-16 10:47:59 [info] [ScheduledTasks] Initialized { accountId: '<account>', orgId: '<orgB>' }
The retry was acked and confirmed — and then the app switched away to the other workspace two seconds later. A session record was written but the CLI was never started.
There is already a guard for this and it is armed for the wrong event. The one firing that worked is the one that was deferred:
09-17 09:40:41 [info] [CCDScheduledTasks] Initialized { accountId: '<account>', orgId: '<orgA>' }
09-17 09:40:41 [info] [CCDScheduledTasks] Deferring check: 11s post-wake delay remaining
09-17 09:41:41 [info] [CCDScheduledTasks] Spawning new session for scheduled task <task>
09-17 09:41:41 [info] [CCDScheduledTasks] Dispatch acknowledged by renderer: <task>
09-17 09:41:41 [info] [CCDScheduledTasks] Confirmed task run for: <task>
60s after Initialized, onto a settled renderer, and it worked. There are 188 Deferring check: 60s post-wake lines in my log — but zero around either lost dispatch, because those were workspace switches, not system wakes.
3. A run that never started still reports succeeded, and lastRunAt advances anyway
Diffing the dead 09-16 session record against the working 09-17 one:
| field | dead run | working run |
|---|---|---|
| cliSessionId | absent | present |
| model | absent | claude-opus-5[1m] |
| completedTurns | absent | 10 |
| toolSurfaceSnapshot | absent | present |
| lastActivityAt | == createdAt, to the millisecond | advances |
| transcript file | none on disk | present |
The record has no status and no error field at all, so status appears to be derived as "not running + no error ⇒ succeeded" — which a never-started run satisfies vacuously. list_task_runs duly reports succeeded.
Worse, lastRunAt is stamped on ack, not on completion. The 09-15 dispatch produced no session record whatsoever, yet the next day's spawn log carries lastRunAt: '2026-09-15T14:25:48.324Z' — the ack timestamp to the millisecond. So that firing is invisible to list_task_runs (totalRuns was 2, not 3) while still counting as the last run and consuming the cron slot.
Impact
Any scheduled task that writes data is silently exposed. A burst designed to collect N samples quietly under-collects, and neither the run list, the succeeded status, nor lastRunAt will tell you. The only reliable signal is the task's own output file, which means every data-collecting task has to be written to verify its own writes landed.
Expected behavior
- The post-dispatch settling delay should apply to workspace-switch/
Initializeddispatches, not only to system wake. - A dispatch should not be acked — and the cron slot should not be consumed, nor
lastRunAtstamped — until the session has actually started (has acliSessionId). - A run whose CLI never started should report
failed, notsucceeded. "Not running and no error recorded" is not sufficient evidence of success. - Ideally, cron evaluation should not depend on which workspace happens to be active.
Steps to reproduce
- Have two workspaces/orgs in the desktop app.
- Create a local cron scheduled task in workspace A that writes to a file.
- Leave workspace B active across the task's scheduled time.
- Switch to workspace A. The task dispatches immediately on
Initialized. - Observe in
~/Library/Logs/Claude/main.log: either noConfirmed task runfollows the ack, or one does but the session never starts. Either waylist_task_runsreportssucceededand the output file is untouched.
Switching away again within a second or two of the dispatch makes it reproduce more readily.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗