[BUG][Windows] Desktop git-shadow probes leak orphaned git.exe on large SMB repos — timeout kills the Git for Windows launcher, not git; 55 procs / 20 GB in 1 h (follow-up to #86646)

Status Fixed / completed
Reported on v2.1.258
Maintainer reply None cached
Activity 2 comments · opened Sep 16, 2026 · closed Sep 24, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

While a Claude Desktop (Code tab) session has its working directory on a large git repo located on an SMB network share, git.exe processes accumulate at ~8/min and never exit. Each one grows to 500–600 MB and burns CPU. Observed: 55 processes / 20.1 GB within ~1 h; on another day 44 / 9.9 GB in 2 h. The machine then hits low-memory events, the WMI service dies, and fork() starts failing in Git Bash.

The processes are the desktop app's diff-panel probes (spawned by the Electron app, CLAUDE_AGENT_SDK_VERSION=0.3.266, GIT_COMMON_DIR=%APPDATA%\Claude\git-shadow\<id>):

  • git status --ignore-submodules=dirty --porcelain=v2 --branch -z
  • git diff --no-textconv --numstat -M <session-base-commit> / git diff --name-status -M <session-base-commit>
  • git ls-files --others --exclude-standard --full-name :/

cwd of every process = the UNC form of the mapped drive (\\<server>\<share>\...\qsdk\); every one of them has a dead parent. Same signature and same ~8/min rate as #86646 (closed as not planned). Sessions whose cwd is not a git repo, or is a repo on a local disk, are unaffected.

What Should Happen?

A probe that exceeds its timeout should be terminated together with any child process, and no new probe should start while the previous one is still running. Worst case: the diff panel stays empty for that repo. It must never leave hundreds of orphaned git.exe processes or exhaust system memory.

Error Messages/Logs

# System event log, Microsoft-Windows-Resource-Exhaustion-Detector, id 2004 (16 events on 2026-09-11)
Windows successfully diagnosed a low virtual memory condition ...

# WMI dies under the load
Get-CimInstance : ... HRESULT 0x80041033 (WBEM_E_SHUTTING_DOWN)

# Git Bash while ~30 orphans were alive
bash: fork: retry: Resource temporarily unavailable
dofork: child -1 - forked process died unexpectedly, exit code 0xC000012D (STATUS_COMMITMENT_LIMIT)

# After moving mingw64\bin ahead of cmd on PATH (so the timeout hits the real git): git killed mid-write
0-byte .git/index.lock left in the repo on the server (twice in one session)

Steps to Reproduce

  1. Windows 11, Git for Windows 2.54 installed the default way (C:\Program Files\Git\cmd on PATH — git resolves to the 45 KB cmd\git.exe launcher, which spawns mingw64\bin\git.exe).
  2. Have a large git repo (ours: 176,202 tracked files, OpenWrt/QSDK) on an SMB share mounted as a drive letter (e.g. R:). A cold git status there takes ≥20 s (GIT_TRACE_PERFORMANCE=1 → preload index: 20.3 s); Windows' SMB directory cache TTL is 10 s, so probes spaced further apart are always cold.
  3. Open a Claude Desktop (Code tab) session with that repo root as the working directory. Do nothing else — the probes run regardless of whether the diff panel is open.
  4. Watch Get-Process git for 5 minutes: count rises ~8/min, none exit, working set grows to 500–600 MB each.
  5. Read any of them with a PEB reader: parent PID is dead; env PATH starts with ...\Git\mingw64\libexec\git-core and MSYSTEM=MINGW64 → spawned via the launcher.

Isolated reproduction of the kill bug (no Claude needed):

  1. Start-Process 'C:\Program Files\Git\cmd\git.exe' 'status' in the repo; after 3 s call TerminateProcess on that PID (what Node's execFile({timeout}) does). The real mingw64\bin\git.exe keeps running with a dead parent.
  2. Repeat with mingw64\bin\git.exe started directly → terminating it leaves nothing behind. (In the app, reordering PATH only slowed accumulation — 30 procs in 20 min — and left 0-byte index.lock files; so the kill target is not the only issue.)

Claude Model

Not sure / Multiple models

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.258 (desktop bundle). The git-shadow probe infrastructure appeared with 2.1.260 (changelog: "Added a diff panel ... shows your uncommitted changes"); our sessions resumed under 2.1.260 on 2026-09-09 08:26 and the first low-memory event was 2026-09-09 17:23.

Claude Code Version

2.1.267 (Claude Code) — CLI. The affected component is the Claude Desktop (Microsoft Store) app 1.49585.0 → 1.52386.6 with bundled Claude Code 2.1.260 → 2.1.266 (%APPDATA%\Claude\claude-code\2.1.266\claude.exe).

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other

Additional Information

Root cause (three factors, all verified):

  1. Probe cost vs timeout: execFile(..., {timeout: 5000}) (jfe=5e3 in app.asar) vs ≥20 s cold git status on this repo over SMB → every probe times out.
  2. The timeout kills the wrong process: git resolves to the Git for Windows cmd\git.exe launcher; TerminateProcess(launcher) does not propagate to its child, so the real mingw64\bin\git.exe is orphaned and keeps scanning (steps 6–7 above).
  3. No in-flight guard: the next probe starts while the previous one is still running, so accumulation rate = spawn rate. Each orphan holds a full fscache (500–600 MB) and contends for the same share, making the next probe slower — positive feedback.

Timeline: 2026-09-04 %APPDATA%\Claude\git-shadow\ created (bundle 2.1.260 downloaded) → 2026-09-09 02:18 desktop 1.46388.4→1.49585.0, 08:26 sessions resumed on 2.1.260 → 17:23 first low-memory event → 2026-09-11 55 procs / 20 GB.

Suggested fixes:

  • Kill the whole process tree on timeout (Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, or taskkill /T).
  • In-flight guard + back-off after a timeout.
  • Skip (or make opt-out) the diff-panel probes when the work tree is on a network share (GetDriveType == DRIVE_REMOTE / UNC) or the index has > N entries; or probe once per turn instead of periodically.
  • Probes should never write into the user's .git (the index.lock leftovers broke one of our build scripts silently).

Workaround for users: don't root desktop sessions in a repo on a network drive; kill orphans with Get-Process git | Stop-Process (probes are read-only). Reordering PATH only slows the leak.

Related: #86646 (same commands, same rate, same Windows build; closed without root cause) — please consider reopening or linking, #94478

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗