Preflight Checklist
What's Wrong?
On Windows, every Bash tool call, the status line, and git's credential helper all start dying with
Exit code 5
0 [main] bash (9800) C:\Program Files\Git\bin\..\usr\bin\bash.exe: *** fatal error - add_item ("\??\C:\Program Files\Git", "/", ...) failed, errno 1
after a 15 second hang. Once it starts it doesn't stop until every MSYS process on the machine is gone, which in practice means a reboot. #30165 reported the symptom. This is the mechanism, and why Claude Code's own status line polling is what turns a rare MSYS race into a permanent outage.
The MSYS bug (msys2-runtime, same code in 3.4.7 and 3.6.10; tracked as git-for-windows/git#6368, fix pending in msys2/msys2-runtime#333). Every MSYS process (bash.exe, sh.exe, ...) maps a per-user shared memory section at startup. The first one to map it builds the mount table under a spinlock that gives up after 15 s and lets the waiter initialise anyway. The section only exists while some MSYS process has it mapped. If the initialiser dies inside the critical section (a process tree being terminated while a shell is starting, or an init that takes more than 15 s), the lock is stuck at -1. Every newcomer then waits 15 s, re-runs mount_info::init on the already built table, and dies in create_root_entry with EPERM, without ever resetting the lock.
Why Claude Code makes it permanent. On Windows a statusLine command runs as bash.exe -c "<command>" through Git Bash, once per refresh, per session. With refreshInterval: 1 and three sessions open that is three fresh MSYS cold starts every second, and each crashing victim spins for 15 s before it dies. So there is always a new holder alive when the last one dies, and the poisoned section is never released. I checked this by enumerating processes with msys-2.0.dll loaded: nothing but 15-second-old bash processes, all -c "node ~/.claude/statusline.mjs", for as long as I watched. With nothing long-lived around, the section is also being torn down and rebuilt many times a minute, so every rebuild is a fresh chance to lose the race in the first place.
Downstream: git's credential.helper = manager runs through sh -c, so HTTPS fetch/push fail with "could not read Username"; every Bash tool call fails; hooks in shell form fail.
What Should Happen?
Any one of these would fix it from Claude Code's side, without waiting for the runtime patch:
- Keep one long-lived MSYS process alive while any session is running (for example
usr\bin\sleep.exe infinity, non-elevated). The shared section then gets initialised once, by a process nothing is racing, and every later bash start takes the fast path (locktest == wanted_val, no spinning). This is the usual CI workaround for this bug (keep a common MSYS parent alive), and it's what I run locally now as a logon task: cold starts went to 28 to 37 ms and it hasn't come back.
- Let
statusLine run in exec form, with the args array hooks already support, so a node or powershell status line doesn't need a bash wrapper on Windows at all. The 2.1.278 schema only accepts type, command, padding, refreshInterval and hideVimModeIndicator.
- Recognise the fatal and recover: when a spawned
bash exits with this exact message, kill every process with msys-2.0.dll loaded (in the poisoned state all of them are already doomed) so the section is released, instead of retrying into the same wall every second.
Steps to Reproduce
Hard to trigger on purpose from outside the DLL, but this shape reliably produces it:
- Windows 11, Git for Windows, a
statusLine with refreshInterval: 1, three or more sessions open.
- Run an orchestration that terminates worker sessions' process trees while they are busy (shells starting and stopping), under CPU load.
- At some point one
bash start dies with the add_item ... errno 1 fatal after a 15 s hang, and from then on every one does. Get-Process | ? { $_.Modules.ModuleName -contains 'msys-2.0.dll' } shows nothing but young bash processes.
- Kill every MSYS process (or reboot) and it works again. Stop the status line churn and the poisoned state clears within 15 s on its own; keep it running and it never does.
Claude Code Version
2.1.278
Operating System
Windows 11 Pro 10.0.26100, not domain-joined (so this is not the slow AD lookup variant in git-for-windows/git#6368)
Terminal/Shell
Windows Terminal, Git for Windows 2.42.0.windows.2 (msys2-runtime 3.4.7)
Additional Information
Related: #30165 (same symptom, closed and locked), git-for-windows/git#6368 (mechanism, slow lookup trigger), msys2/msys2-runtime#333 (runtime fix, waiting on upstream submission to cygwin-patches).
Preflight Checklist
What's Wrong?
On Windows, every Bash tool call, the status line, and git's credential helper all start dying with
after a 15 second hang. Once it starts it doesn't stop until every MSYS process on the machine is gone, which in practice means a reboot. #30165 reported the symptom. This is the mechanism, and why Claude Code's own status line polling is what turns a rare MSYS race into a permanent outage.
The MSYS bug (msys2-runtime, same code in 3.4.7 and 3.6.10; tracked as git-for-windows/git#6368, fix pending in msys2/msys2-runtime#333). Every MSYS process (
bash.exe,sh.exe, ...) maps a per-user shared memory section at startup. The first one to map it builds the mount table under a spinlock that gives up after 15 s and lets the waiter initialise anyway. The section only exists while some MSYS process has it mapped. If the initialiser dies inside the critical section (a process tree being terminated while a shell is starting, or an init that takes more than 15 s), the lock is stuck at-1. Every newcomer then waits 15 s, re-runsmount_info::initon the already built table, and dies increate_root_entrywithEPERM, without ever resetting the lock.Why Claude Code makes it permanent. On Windows a
statusLinecommand runs asbash.exe -c "<command>"through Git Bash, once per refresh, per session. WithrefreshInterval: 1and three sessions open that is three fresh MSYS cold starts every second, and each crashing victim spins for 15 s before it dies. So there is always a new holder alive when the last one dies, and the poisoned section is never released. I checked this by enumerating processes withmsys-2.0.dllloaded: nothing but 15-second-oldbashprocesses, all-c "node ~/.claude/statusline.mjs", for as long as I watched. With nothing long-lived around, the section is also being torn down and rebuilt many times a minute, so every rebuild is a fresh chance to lose the race in the first place.Downstream: git's
credential.helper = managerruns throughsh -c, so HTTPS fetch/push fail with "could not read Username"; every Bash tool call fails; hooks in shell form fail.What Should Happen?
Any one of these would fix it from Claude Code's side, without waiting for the runtime patch:
usr\bin\sleep.exe infinity, non-elevated). The shared section then gets initialised once, by a process nothing is racing, and every laterbashstart takes the fast path (locktest == wanted_val, no spinning). This is the usual CI workaround for this bug (keep a common MSYS parent alive), and it's what I run locally now as a logon task: cold starts went to 28 to 37 ms and it hasn't come back.statusLinerun in exec form, with theargsarray hooks already support, so anodeorpowershellstatus line doesn't need abashwrapper on Windows at all. The 2.1.278 schema only acceptstype,command,padding,refreshIntervalandhideVimModeIndicator.bashexits with this exact message, kill every process withmsys-2.0.dllloaded (in the poisoned state all of them are already doomed) so the section is released, instead of retrying into the same wall every second.Steps to Reproduce
Hard to trigger on purpose from outside the DLL, but this shape reliably produces it:
statusLinewithrefreshInterval: 1, three or more sessions open.bashstart dies with theadd_item ... errno 1fatal after a 15 s hang, and from then on every one does.Get-Process | ? { $_.Modules.ModuleName -contains 'msys-2.0.dll' }shows nothing but youngbashprocesses.Claude Code Version
2.1.278
Operating System
Windows 11 Pro 10.0.26100, not domain-joined (so this is not the slow AD lookup variant in git-for-windows/git#6368)
Terminal/Shell
Windows Terminal, Git for Windows 2.42.0.windows.2 (msys2-runtime 3.4.7)
Additional Information
Related: #30165 (same symptom, closed and locked), git-for-windows/git#6368 (mechanism, slow lookup trigger), msys2/msys2-runtime#333 (runtime fix, waiting on upstream submission to cygwin-patches).