Bash tool: PATH not Windows->POSIX translated when MSYS bash subprocess respawns mid-session
Summary
Mid-session, after some harness state change, the Bash tool's persistent MSYS bash subprocess starts returning command not found for gh, node, rm, ls, head, which, date, and other binaries. git continues to work. Root cause is that the bash subprocess is spawned with the un-translated Windows-style PATH (semicolon-separated C:\... entries), which MSYS bash cannot parse as POSIX path entries.
The harness then appends a single POSIX-style path at the end with :, producing a malformed mixed-format PATH. Bash treats the entire Windows prefix as one giant non-existent directory name; only the trailing POSIX-appended entry is usable.
Environment
- Claude Code: 2.1.161 (Electron desktop build)
- Platform: Windows 11
- Shell: Git for Windows MSYS bash (
C:\Program Files\Git\bin\bash.exe) - Symptom appeared mid-session after harness state recovery (correlates with a brief
claude-opus-4-7 is temporarily unavailableclassifier downtime event ~3 minutes earlier, suggesting bash respawn during recovery)
Reproduction
Inside a long-running session where the Bash tool initially works fine:
- Some harness state change occurs (in my case: classifier supervisor downtime + recovery)
- The harness re-spawns its persistent bash subprocesses
- From this point forward, every Bash tool call observes broken PATH
Evidence — direct $PATH dump from inside Bash tool
(Username + skills-plugin install path redacted for public issue; the structural shape is what matters.)
PATH=C:\Python314\Scripts\;C:\Python314\;C:\Python313\Scripts\;C:\Python313\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\GitHub CLI\;C:\Users\<user>\AppData\Local\Microsoft\WindowsApps;C:\Users\<user>\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\<user>\AppData\Roaming\npm;C:\Users\<user>\AppData\Local\Programs\Ollama;C:\Users\<user>\.local\bin;C:\Program Files\nodejs;C:\Python314;C:\Python313;C:\Program Files\Git\mingw64\bin:/c/Users/<user>/AppData/Roaming/Claude/local-agent-mode-sessions/skills-plugin/<uuid>/<uuid>/bin
The PATH is almost entirely semicolon-separated Windows C:\... paths — except the very last segment is colon-prefixed POSIX /c/... path appended by the harness for its skills-plugin bin directory.
MSYS bash uses : as the POSIX path separator. So it parses this as two entries:
C:\Python314\Scripts\;C:\Python314\;...;C:\Program Files\Git\mingw64\bin— one giant directory name, doesn't exist on disk/c/Users/<user>/AppData/Roaming/Claude/local-agent-mode-sessions/skills-plugin/<uuid>/<uuid>/bin— the only valid PATH entry
git happens to live in that plugin bin directory, which is why it keeps working. Everything else fails with command not found.
Process-tree evidence
Two persistent bash.exe subprocesses live for the entire session:
PID <n> bash StartTime: 2026-06-06T04:50:08Z (= local 11:50:08 PM) C:\Program Files\Git\bin\bash.exe
PID <n+1> bash StartTime: 2026-06-06T04:50:08Z C:\Program Files\Git\bin\..\usr\bin\bash.exe
The session started ~12 hours before the bash respawn. For the first ~12 hours, all gh/node calls in Bash worked correctly. After the respawn at 04:50:08Z, every Bash call has observed the broken PATH.
No ~/.bashrc or ~/.bash_profile exists for the user, so PATH comes purely from what the harness passes via environment when spawning the subprocess.
PowerShell tool (separate Windows subprocess) sees a clean Windows PATH with proper ; separators and works normally.
Suggested fix
In the bash-subprocess spawn code path, translate Windows-style PATH to POSIX before passing to the child process. Something like:
function win32PathToPosix(winPath: string): string {
return winPath
.split(';')
.filter(p => p.length > 0)
.map(p => {
// C:\Foo\Bar -> /c/Foo/Bar
const m = p.match(/^([A-Za-z]):[\\/](.*)$/);
if (m) return `/${m[1].toLowerCase()}/${m[2].replace(/\\/g, '/')}`;
return p;
})
.join(':');
}
// In the bash spawn:
const env = {
...process.env,
PATH: process.platform === 'win32'
? win32PathToPosix(process.env.PATH) + ':' + skillsPluginBin
: process.env.PATH + ':' + skillsPluginBin,
};
spawn(bashPath, args, { env });
The translation needs to apply on every bash subprocess spawn, including respawns triggered by harness state recovery.
Why "intermittent" — the time correlation
In my session, the original bash subprocess (presumably spawned at session start) had a correctly POSIX-translated PATH and worked for ~12 hours. The respawn at 04:50:08Z did not apply the same translation, suggesting the respawn code path is missing the translation step that the initial-spawn code path has. The fix would need to land in whichever code path handles respawn, not just initial spawn.
Workaround
PowerShell tool works (Windows-native PATH semantics, no separator mismatch). For the rest of an affected session, route gh/node/coreutils calls through PowerShell instead of Bash. git calls continue to work in Bash.
Impact
Silent degradation of the Bash tool's capability mid-session, with confusing command not found errors that look like user environment misconfiguration rather than a harness PATH bug. The shell itself still runs (so the tool doesn't "fail"), but most cross-platform tooling becomes unreachable.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗