[BUG] v2.1.45: Bash tool fails with exit code 1 on Windows (MSYS2 stdout pipe issue)

Resolved 💬 2 comments Opened Feb 18, 2026 by lukeloxton1 Closed Feb 19, 2026

Describe the bug

After updating to v2.1.45, all Bash tool invocations fail with Exit code 1 and produce zero output. This includes trivial commands like \echo hello\ and \pwd\. Bash worked correctly in v2.1.44 and earlier.

This is a duplicate/confirmation of #26413, #26462, and #26486, with additional diagnostic details.

To reproduce

Environment:

  • Windows 11 Pro 10.0.26200
  • Git Bash installed at \C:\Program Files\Git\
  • Claude Code v2.1.45

Steps:

  1. Update Claude Code to v2.1.45
  2. Run any Bash tool command (e.g., \echo hello\, \pwd\, \ls\)
  3. Observe: Exit code 1, no output

Observed behavior

| Command | Result |
|---------|--------|
| \echo hello\ | Exit code 1, no output |
| \pwd\ | Exit code 1, no output |
| \ls -la\ | Exit code 2, no output |
| \true\ | Exit code 0 (success) |
| \echo hello > file.txt\ | Exit code 0, file written successfully |
| \git --version\ | Works (native .exe) |
| \claude --version\ | Works (native .exe) |

Pattern: Native Windows executables work. Bash builtins and commands that write to stdout/stderr fail. Commands that only write to files (bypassing stdout) succeed.

Root cause (confirmed by @frostbtn in #26413)

v2.1.45 changed the \spawn()\ call to use file-based stdout/stderr capture:

Broken (v2.1.45):
\\\js
spawn(bashPath, args, {
stdio: ["pipe", fileDescriptor, fileDescriptor], // fileDescriptor from fs.openSync()
...
})
\
\\

Working (v2.1.44):
\\\js
spawn(bashPath, args, {
// stdio omitted → Node.js uses pipe streams
...
})
\
\\

When MSYS2 bash (Git Bash) inherits a Windows file descriptor (from \openSync\) as its stdout, the MSYS2 POSIX compatibility layer cannot recognize it as POSIX fd 1. Bash then falls back to writing to the console instead of the pipe. Claude Code reads the empty file/pipe and reports exit code 1.

File redirects inside bash still work (\echo hello > file\) because bash opens a fresh fd for that redirect, bypassing the broken inherited fd 1.

Diagnostic details

Ruled out:

  • \.bashrc\ / \.bash_profile\ startup errors (tested with \--norc --noprofile\)
  • \BASH_ENV\ environment variable (not set)
  • \bash.cmd\ wrapper interference (Claude Code spawns \bash.exe\ directly via \CreateProcess\)
  • PATH resolution issues (multiple bash paths tested)
  • MSYS2 environment variables (\MSYSTEM\, \HOME\) — no effect

Key diagnostic that revealed the issue:

  • \true\ → success (no I/O needed)
  • \echo hello\ → exit 1 (writes to stdout)
  • \echo hello >&2\ → exit 1 (stderr also broken)
  • \echo hello > "C:/path/to/file.txt"\ → success (file write bypasses broken pipe)

This confirmed the issue is specifically with stdout/stderr pipe inheritance, not bash startup or PATH.

Expected behavior

Bash tool should execute commands and capture stdout/stderr correctly, as it did in v2.1.44.

Workaround

Downgrade to v2.1.44:

\\\powershell
curl -fsSL https://claude.ai/install.cmd -o ./install.cmd
./install.cmd 2.1.44
del install.cmd
\
\\

Environment

  • Claude Code version: 2.1.45
  • OS: Windows 11 Pro 10.0.26200
  • Shell: bash (Git Bash, GNU bash 5.2.37(1)-release)
  • Git Bash path: \C:\Program Files\Git\usr\bin\bash.exe\
  • WSL: Not installed

Related issues

  • #26413 — Bash tool: all commands fail with Bad file descriptor on Windows
  • #26462 — v2.1.45: Bash broken on Windows - bad file descriptor on stdout pipe
  • #26486 — Bash tool broken on Windows: Git Bash MSYS2 Bad file descriptor with piped stdout

Credit to @frostbtn for identifying the exact \spawn()\ difference in #26413.

View original on GitHub ↗

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