claude-code - 💡(How to fix) Fix Scheduled-task runner leaks claude-code subprocesses (build 2.1.121) [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#55607Fetched 2026-05-03 04:49:04
View on GitHub
Comments
2
Participants
2
Timeline
9
Reactions
0
Timeline (top)
labeled ×5commented ×2closed ×1cross-referenced ×1

The local-agent-mode scheduled-task runner in Claude Desktop 1.5354.0 (using bundled claude-code/2.1.121) does not tear down spawned runner subprocesses after a scheduled task completes. Each fire leaks one disclaimer wrapper + one claude child, both stuck in interruptible sleep (S) on stdio. After ~24 hours of normal cron activity (~7 fires/hr), ~200 stuck pairs accumulate. Once the renderer's internal subprocess cap is reached, the dispatcher silently swallows further fires — nextRunAt advances past missed slots without spawning a runner.

Error Message

  1. After enough accumulation, scheduled tasks stop firing entirely while the desktop UI shows no error.
  • No error surfaces in the Claude Desktop UI, log files, or notifications

Root Cause

  • All scheduled tasks silently stop firing after the cap is hit
  • No error surfaces in the Claude Desktop UI, log files, or notifications
  • Recovery requires manually killing the entire pile (pkill -f claude-code/2.1.121) ‚Äî no in-app reset
  • The watchdog/heartbeat task pattern Anthropic users rely on (e.g. a daily cron-heartbeat task that pings if any other task is stale) doesn't catch this because the heartbeat itself is one of the silently-skipped tasks

Fix Action

Fix / Workaround

The local-agent-mode scheduled-task runner in Claude Desktop 1.5354.0 (using bundled claude-code/2.1.121) does not tear down spawned runner subprocesses after a scheduled task completes. Each fire leaks one disclaimer wrapper + one claude child, both stuck in interruptible sleep (S) on stdio. After ~24 hours of normal cron activity (~7 fires/hr), ~200 stuck pairs accumulate. Once the renderer's internal subprocess cap is reached, the dispatcher silently swallows further fires — nextRunAt advances past missed slots without spawning a runner.

Workaround in place locally

RAW_BUFFERClick to expand / collapse

Bug — Claude Desktop scheduled-task runner leaks claude-code subprocesses

Summary

The local-agent-mode scheduled-task runner in Claude Desktop 1.5354.0 (using bundled claude-code/2.1.121) does not tear down spawned runner subprocesses after a scheduled task completes. Each fire leaks one disclaimer wrapper + one claude child, both stuck in interruptible sleep (S) on stdio. After ~24 hours of normal cron activity (~7 fires/hr), ~200 stuck pairs accumulate. Once the renderer's internal subprocess cap is reached, the dispatcher silently swallows further fires — nextRunAt advances past missed slots without spawning a runner.

Repro

  1. Configure any local-agent-mode scheduled task with a frequent cron (e.g. every 15 min).
  2. Leave Claude Desktop running for 24h.
  3. Observe ps -ax | grep 'claude-code/2.1.121/claude.app/Contents/MacOS/claude' | wc -l climbing monotonically.
  4. After enough accumulation, scheduled tasks stop firing entirely while the desktop UI shows no error.

The bug reproduces independently of:

  • Which model the task uses (observed across claude-opus-4-7, claude-sonnet-4-6, claude-sonnet-4-5-20250929, default)
  • Permission mode (observed across bypassPermissions and default)
  • The skill content (no skills in the affected setup spawn background processes; verified by grep -rE 'nohup|disown|setsid|& *$' ~/.claude/scheduled-tasks/)
  • User-configured hooks (no Stop / PostToolUse hook configured)

Process signature

Each leaked pair has:

Outer (disclaimer wrapper):

  • argv0: /Applications/Claude.app/Contents/Helpers/disclaimer
  • argv: includes the full path to claude and all its flags
  • ppid: Claude.app/Contents/MacOS/Claude (main process)

Inner (claude runner):

  • argv0: /Users/<user>/Library/Application Support/Claude/claude-code/2.1.121/claude.app/Contents/MacOS/claude
  • ppid: the outer disclaimer process
  • relevant flags: --output-format stream-json --input-format stream-json --permission-prompt-tool stdio --allow-dangerously-skip-permissions --include-partial-messages --replay-user-messages --settings {}
  • state: S (interruptible sleep)
  • RSS: ~80 MB, stable

The combination of --input-format stream-json and --permission-prompt-tool stdio means the child reads from stdin until EOF. The hang signature is consistent with the parent (Claude Helper Renderer hosting the local-agent-mode runner) failing to close the child's stdin pipe when the skill's Stop event fires.

Environment

  • Claude Desktop version: 1.5354.0
  • claude-code build: 2.1.121 (bundled in Claude.app)
  • macOS: 25.1.0 (Darwin)
  • Scheduled-tasks feature: ccdScheduledTasksEnabled: true + coworkScheduledTasksEnabled: true

Impact

  • All scheduled tasks silently stop firing after the cap is hit
  • No error surfaces in the Claude Desktop UI, log files, or notifications
  • Recovery requires manually killing the entire pile (pkill -f claude-code/2.1.121) ‚Äî no in-app reset
  • The watchdog/heartbeat task pattern Anthropic users rely on (e.g. a daily cron-heartbeat task that pings if any other task is stale) doesn't catch this because the heartbeat itself is one of the silently-skipped tasks

Workaround in place locally

A janitor launchd agent (com.alex.argus.claude-janitor, every 10 min) reaps claude-code/2.1.121 processes whose parent's command contains Claude.app AND whose elapsed time exceeds 30 min. Hard-coded to build 2.1.121 so it auto-no-ops once a fixed build ships. Source available on request.

What would help

  1. Fix: have the runner explicitly close child stdio (or kill -9 the child) when the skill's Stop event fires — preferably with a 30-second hard-deadline regardless of pipe state.
  2. Telemetry: surface a UI warning when pending child-runner count exceeds, say, 20. Right now the failure is invisible until the user manually ps-greps.
  3. Recovery: an in-app "Restart scheduled-tasks runner" button or auto-reaper for orphaned local-agent-mode subprocesses older than 30 min.

Local diagnosis report

Full investigation, evidence, and ruled-out hypotheses: ~/Documents/Claude by Alex/Reports/2026-05-01 stuck-cron-process-diagnosis.md

extent analysis

TL;DR

The most likely fix is to modify the runner to explicitly close child stdio or kill the child process when the skill's Stop event fires.

Guidance

  • Verify the issue by checking the process list for leaked claude-code subprocesses after a scheduled task completes.
  • Implement a fix by modifying the runner to close child stdio or kill the child process when the skill's Stop event fires, with a 30-second hard deadline.
  • Consider adding telemetry to surface a UI warning when the pending child-runner count exceeds a certain threshold.
  • Implement an in-app recovery mechanism, such as a "Restart scheduled-tasks runner" button or auto-reaper for orphaned subprocesses.

Example

No code snippet is provided as the issue does not contain sufficient information to create a specific example.

Notes

The provided workaround using a janitor launchd agent may not be a permanent solution and may need to be updated or removed once a fixed build is shipped.

Recommendation

Apply the workaround using a janitor launchd agent until a fixed build is available, as it provides a temporary solution to reap leaked processes and prevent the accumulation of stuck subprocesses.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix Scheduled-task runner leaks claude-code subprocesses (build 2.1.121) [2 comments, 2 participants]