[BUG] Desktop: one-time scheduled task (enabled:false after firing) gets re-confirmed and re-fired in a loop — 21 fires in 6 min, one plan-mode session each
Summary
A one-time scheduled task created from the desktop app (via the scheduled-tasks MCP: create_scheduled_task) fired once as expected, was auto-disabled, and then was re-confirmed and re-fired in a loop by the app several hours later: 21 fires in about six minutes, each one opening a new plan-mode session with no prompt. The loop only stopped when the task was deleted.
Environment
| | |
|---|---|
| Claude desktop app | 1.44121.2 (macOS) |
| Claude Code (bundled CLI) | 2.1.259 |
| OS | macOS 26.6.2 (Darwin 25.6.0, arm64) |
| Task | one-time (fireAt), created the same day, fired correctly at 06:38 local, then showed enabled: false |
What we observed (2026-09-03, 18:30 to 18:36 local)
~/Library/Logs/Claude/main.log (task name redacted to <task>):
2026-09-03 18:32:57 [warn] [CliGovernor] memory pressure (warning): evicted 1 of 1 idle session(s), 11 effective
2026-09-03 18:33:06 [info] [CCDScheduledTasks] Confirmed task run for: <task>
2026-09-03 18:33:06 [info] [CCDScheduledTasks] Auto-disabled one-time task after fire: <task>
2026-09-03 18:33:09 [info] [CCDScheduledTasks] Confirmed task run for: <task>
2026-09-03 18:33:09 [info] [CCDScheduledTasks] Auto-disabled one-time task after fire: <task>
2026-09-03 18:33:10 [info] [CCDScheduledTasks] Confirmed task run for: <task>
2026-09-03 18:33:10 [info] [CCDScheduledTasks] Auto-disabled one-time task after fire: <task>
2026-09-03 18:33:11 [info] [CCDScheduledTasks] Confirmed task run for: <task>
2026-09-03 18:33:11 [info] [CCDScheduledTasks] Auto-disabled one-time task after fire: <task>
2026-09-03 18:33:40 [info] [CCDScheduledTasks] Confirmed task run for: <task>
2026-09-03 18:33:40 [info] [CCDScheduledTasks] Auto-disabled one-time task after fire: <task>
...
Process table at 18:34 (ps -axo pid,lstart,etime,command, trimmed): one claude ... --permission-mode plan process per fire, born 1 to 3 seconds apart:
76144 18:33:06 2026 01:40 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
76145 18:33:06 2026 01:40 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
76269 18:33:09 2026 01:37 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
76270 18:33:09 2026 01:37 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
76303 18:33:10 2026 01:36 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
76304 18:33:10 2026 01:36 | --output-format stream-json --input-format stream-json --model default --permission-mode plan
Totals for the day: 23 fires of a task that should fire once; 21 of them between 18:30 and 18:36:39 (about 7 per minute); 38 plan-mode claude processes alive at the peak; 1-minute load average 8.5 on an otherwise idle machine; each spawned session ran the repo's SessionStart hooks (22 to 30 s each in our case).
What stopped it
Deleting the task (delete_scheduled_task) at 18:40. Within a minute: 0 plan-mode processes. The app then archived the 22 sessions it had opened. Leaving the task in place as enabled: false (its state after the first, correct fire) was not enough.
Expected
- A one-time task that has fired and is
enabled: falseshould never be confirmed or run again. - If the scheduler re-reads its store (the log suggests a "confirm" loop, possibly triggered around the governor's memory-pressure eviction a few seconds earlier), it should treat disabled one-time tasks as terminal.
- A safety net would help regardless of cause: refuse to fire the same task id more than once per N seconds, and surface a visible warning instead of silently spawning sessions.
Steps to reproduce (what we did; not yet reduced)
- Create a one-time task from a desktop session with
create_scheduled_task(fireAta few minutes ahead). - Let it fire once; confirm
list_scheduled_tasksshows itenabled: false. - Leave the app running with several other sessions for a few hours (memory pressure eviction was logged 9 s before the loop started).
- Watch
main.logfor repeatedConfirmed task run/Auto-disabled one-time task after firepairs for the same task id.
We have the full main.log excerpt and process table captures and can share them.