Claude Desktop (macOS): scheduled-task session processes never exit after the run completes; WarmLifecycle disconnect loops forever and per_task_limit jams

Status Closed — duplicate
Reported on v2.1.219
Maintainer reply None cached
Activity 1 comment · opened Aug 2, 2026 · closed Aug 25, 2026

Environment

  • Claude Desktop for macOS, bundled Claude Code CLI 2.1.219 (~/Library/Application Support/Claude/claude-code/2.1.219/claude.app/Contents/MacOS/claude, launched via Claude.app/Contents/Helpers/disclaimer)
  • macOS Darwin 25.5.0, Mac mini (Apple silicon), Max plan
  • Remote control auto-enable is ON ([rcAutoEnable] verdict: enable=true source=explicit_pref)

What happens

Scheduled tasks configured in the Desktop app (CCDScheduledTasks) spawn a headless local session per run. The run itself completes fine (transcript shows the finished work and a custom-title event after ~3 minutes), but the CLI child process never exits. main.log then repeats forever, every 900 s, for days:

[WarmLifecycle:session] Idle timeout reached, disconnecting local_<id>
[WarmLifecycle:session] Starting idle timeout for local_<id>: 900s

One zombie per scheduled run accumulates. Observed: five processes over five days (2026-07-29 to 2026-08-02, one daily task at 06:58 plus one other task run), each ~140-160 MB RSS plus their stdio MCP server children, with steadily growing swap. On another Mac this same leak previously escalated to ~97 leaked session processes in a day (2026-07-09), which exhausted swap and made fresh claude spawns hang until the app was restarted.

A stuck session also permanently occupies the task's dispatch slot. Logged every minute, indefinitely:

[CCDScheduledTasks] Skipping dispatch for <task>: per_task_limit (active=1, limit=1)

so further runs of that task are silently skipped until the zombie is killed externally.

Spawn-to-zombie timeline (sanitized log excerpts)

06:58:34 [CCDScheduledTasks] Spawning new session for scheduled task morning-briefing { cronExpression: '50 6 * * *', ... }
06:58:39 Using Claude Code binary at: .../claude-code/2.1.219/claude.app/Contents/MacOS/claude
06:58:39 [WarmLifecycle:session] Starting idle timeout for local_<id>: 900s
06:58:39 [rcAutoEnable] verdict: enable=true source=explicit_pref
06:58:39 Enabling remote control for session local_<id>
06:58:58 [CCDScheduledTasks] Confirmed task run for: morning-briefing
07:01:xx (run completes; transcript stops)
07:13:39 [WarmLifecycle:session] Idle timeout reached, disconnecting local_<id>
07:13:39 [WarmLifecycle:session] Starting idle timeout for local_<id>: 900s
... repeats every 900 s for days ...

Every zombie had remote control enabled at spawn; a plausible mechanism is that the remote-control bridge registration keeps the WarmLifecycle disconnect from ever finalizing, so the process is retained for remote attach forever.

Expected

Scheduled-task session processes exit (or are reaped) once the run completes, and per_task_limit slots are released.

Confirmations

  • Externally SIGTERMing a zombie is handled cleanly: the app logs Claude Code process exited with code 143, and a jammed task dispatches its pending run within seconds.
  • The runs themselves are healthy; only process teardown fails.

Workaround

An external hourly watcher that SIGTERMs Desktop-CLI session processes (claude-code/<ver>/claude.app/Contents/MacOS/claude) older than 24 h with no controlling TTY.

Related minor issue

The task firing in these logs exists in the Desktop app's internal registry but is not returned by the scheduled-tasks MCP (list_scheduled_tasks) on the same machine, so it is invisible to tooling; the two registries appear to have diverged.

View original on GitHub ↗

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