Skip to content

Actually kill the Claude process tree on stop#208

Open
leonidasbarkas98-cpu wants to merge 1 commit into
andrepimenta:mainfrom
leonidasbarkas98-cpu:fix/stop-kill-process-tree
Open

Actually kill the Claude process tree on stop#208
leonidasbarkas98-cpu wants to merge 1 commit into
andrepimenta:mainfrom
leonidasbarkas98-cpu:fix/stop-kill-process-tree

Conversation

@leonidasbarkas98-cpu

Copy link
Copy Markdown

Clicking Stop showed "Claude code was stopped." (plus a misleading red "Error running Claude: The operation was aborted" box) but the work kept running until VS Code was closed.

Root cause is the kill ordering in _killClaudeProcess. abort() ran first: on Windows the tracked PID is the cmd.exe shell from spawn(..., shell: true), so abort() synchronously killed only that shell and set child.killed. The taskkill /pid X /t /f that followed — the correct tree kill — hit an already-dead root, could not enumerate the process tree anymore and failed silently, so the real claude worker (a grandchild) and everything it spawned orphaned and kept running. The pre-set killed flag also turned the exit-wait/SIGKILL escalation into dead code, and the synchronous AbortError surfaced as the red error box.

The fix inverts the order: clear _currentClaudeProcess first (late close/error events hit the handlers' guards and no-op — no false error box), tree-kill while the root is still alive with a 2s exit-wait and SIGKILL escalation (exitCode !== null also covers a death observed during the wait, since taskkill never sets killed), and abort() last as pure cleanup.

All kill paths benefit: the Stop button, New Chat and panel disposal. Unix/WSL branches are untouched.

Addresses #178 and #115. Complementary to #197 (which cancels pending permission requests on stop); the two apply independently.

Based on current main (ab6e307), tsc --noEmit clean, no new dependencies.

Clicking Stop showed 'Claude code was stopped.' (plus a misleading red
'Error running Claude: The operation was aborted' box) but the work
kept running until VS Code was closed (andrepimenta#178, andrepimenta#115).

Root cause is the kill ordering in _killClaudeProcess. abort() ran
first: on Windows the tracked PID is the cmd.exe shell from
spawn(..., shell: true), so abort() synchronously killed only that
shell and set child.killed. The taskkill /pid X /t /f that followed —
the correct tree kill — hit an already-dead root, could not enumerate
the process tree anymore and failed silently (errors are swallowed),
so the real claude worker (a grandchild) and everything it spawned
orphaned and kept running. The pre-set killed flag also turned the
exit-wait/SIGKILL escalation into dead code, and the synchronous
AbortError surfaced as the red error box.

Fix: invert the order.
1. Clear _currentClaudeProcess first (before any await) so close/error
   events firing mid-kill hit the handlers' no-current-process guards
   and no-op — no false error box.
2. Tree-kill (SIGTERM) while the root is still alive, wait up to 2s
   for the exit — 'exitCode !== null' also covers a death Node
   observed during the wait, since taskkill never sets killed — then
   escalate to SIGKILL only if the process is really still running.
3. abort() last, purely as cleanup of the AbortController; its late
   AbortError is dropped by the error handler's guard.

All kill paths benefit: the Stop button, New Chat and panel disposal.
Unix/WSL branches of _killProcessGroup are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant