Bash tool leaks orphaned child processes on Windows timeout (runaway ind / scans accumulate for hours)

Open 💬 0 comments Opened Jul 10, 2026 by tfriedel

Summary

On Windows, when a Bash-tool command exceeds its timeout (or otherwise ends), Claude Code terminates the bash.exe shell but not its descendant processes. Grandchild processes (e.g. find.exe under Git Bash / MSYS2) keep running as orphans. A find / full-filesystem scan therefore keeps crawling the entire disk for hours after the tool call has "ended," and these accumulate across sessions until the machine is heavily loaded.

Environment

  • Claude Code: 2.1.206
  • Model: Opus 4.8 (1M context)
  • OS: Windows 11 Education, 10.0.22631 (build 22631)
  • Shell / Bash-tool backend: Git Bash (MSYS2), git version 2.36.1.windows.1, C:\Program Files\Git\usr\bin\find.exe

Impact

  • Found 10 orphaned find.exe processes alive, spawned over ~4 hours across prior sessions (creation timestamps 2026-07-09 20:09 → 2026-07-10 00:10).
  • Every one was scanning from filesystem root /.
  • Each had accumulated 16,000–26,000 CPU-seconds (4.5–7 CPU-hours) and was still consuming ~10–19% of a core apiece when discovered — collectively saturating the machine.
  • Parent bash.exe shells were all already exited (orphaned ParentProcessId points to a dead PID), so nothing would ever reap them.

Leaked command lines (verbatim)

find.exe / -iname slint-1.17* -maxdepth 6
find.exe / -type d -iname slint-1.17*
find.exe / -path */registry/src/*/slint-1.1*/src/api/window.rs
find.exe / -type d -iname slint-*-examples -o -type d -path *slint*/examples
find.exe / -iname flickable.rs
find.exe / -path *registry/src*/i-slint-compiler* -maxdepth 10
find.exe / -iname midi_mapping.json
find.exe / -iname *.slint -path *examples*
find.exe / -iname *.rs -path *slint*     (x2)

All are unbounded (or barely bounded) recursive scans rooted at /. On Windows/MSYS2 that walks the whole drive, which routinely exceeds the 120s Bash-tool timeout.

Reproduction

  1. On Windows, have Claude Code run a slow full-disk command via the Bash tool, e.g. find / -iname something that takes longer than the tool timeout.
  2. Let the tool call time out (or otherwise end).
  3. Observe: the bash.exe wrapper is gone, but find.exe is still running. Get-CimInstance Win32_Process -Filter "Name='find.exe'" shows it alive with a ParentProcessId whose process no longer exists.

Root cause

The Bash tool does not terminate the full descendant process tree on timeout/cancel/exit on Windows — it appears to kill only the immediate bash.exe. MSYS2 grandchildren survive and keep running. There is no Job Object / process-group kill guaranteeing tree teardown.

Suggested fixes

  • On Windows, launch Bash-tool commands inside a Windows Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, so closing the job kills the entire tree on timeout/cancel/exit.
  • Alternatively, on timeout kill the process tree explicitly (taskkill /T /F on the shell PID, or enumerate + terminate descendants).
  • Consider warning when a Bash command roots a recursive scan at / on Windows.

Note on killing these

For these MSYS2 processes, both taskkill /F /PID ("no instance running") and PowerShell Stop-Process ("cannot find a process") failed, even though the processes were alive and burning CPU. The WMI Win32_Process.Terminate method worked:

Get-CimInstance Win32_Process -Filter "Name='find.exe'" |
  ForEach-Object { Invoke-CimMethod -InputObject $_ -MethodName Terminate }

View original on GitHub ↗