[BUG] Native installer on Windows: bash hooks resolve to WSL bash.exe instead of Git Bash, causing TUI hang with broken timeout

Resolved 💬 3 comments Opened Mar 23, 2026 by gowerlin Closed Mar 26, 2026

Preflight Checklist

  • [x] I have searched existing issues and this has not 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 is Wrong?

On Windows 11 with the native installer (v2.1.81), hooks that invoke bash resolve to C:\Windows\System32\bash.exe (the WSL launcher stub) instead of Git Bash (C:\Program Files\Git\bin\bash.exe). This causes hooks to hang indefinitely, freezing the entire TUI — no input accepted, no commands execute, and the configured timeout on the hook is ignored.

Root Cause

The native installer (claude.exe) spawns hook subprocesses using the system PATH rather than inheriting the launching terminal PATH. On Windows 10/11, C:\Windows\System32\bash.exe (WSL stub) exists by default — even without a full WSL distribution installed. This stub takes priority over Git Bash in the system PATH.

When the hook runs under WSL bash, it enters a different environment that lacks the user SSH keys, jq, git config, and other tools, causing the script to hang waiting for input or network access.

Two Sub-Bugs

  1. PATH resolution change (breaking): Prior versions (launched from Git Bash terminal) inherited the terminal PATH, so bash correctly resolved to Git Bash. v2.1.81 native installer changed this behavior without documentation.
  1. Hook timeout does not kill the process: Even with "timeout": 30000 configured on the hook, the TUI freezes completely. The timeout mechanism fails to terminate the hung subprocess.

Steps to Reproduce

  1. Install Claude Code via native installer on Windows 11
  2. Have Git for Windows installed (C:\Program Files\Git\bin\bash.exe)
  3. Confirm WSL stub exists: where.exe bash shows C:\Windows\System32\bash.exe before Git Bash
  4. Add a bash hook in settings.json:

``json
{
"hooks": {
"SessionStart": [{
"hooks": [{
"type": "command",
"command": "bash \"C:/Users/MyUser/myscript.sh\"",
"timeout": 30000
}]
}]
}
}
``

  1. Launch claude from Git Bash
  2. The TUI freezes — no prompt appears, no input accepted

Expected Behavior

  • Hooks should either inherit the launching terminal PATH, or Claude Code should prefer Git Bash over WSL stub on Windows
  • At minimum, the timeout setting should work and kill hung hook subprocesses instead of freezing the entire TUI

Workaround

Use a Node.js wrapper that calls Git Bash via execFileSync with an absolute path, bypassing PATH resolution entirely:

// bash-wrapper.js
const { execFileSync } = require("child_process");
const fs = require("fs");
const gitBash = "C:/Program Files/Git/bin/bash.exe";
if (!fs.existsSync(gitBash)) process.exit(1);
try {
  execFileSync(gitBash, process.argv.slice(2), {
    stdio: "inherit", timeout: 30000, windowsHide: true
  });
} catch (e) { process.exit(e.status || 0); }

Then in hooks: node bash-wrapper.js myscript.sh

Environment

  • Claude Code: v2.1.81 (native installer)
  • OS: Windows 11
  • Terminal: Git Bash (MINGW64)
  • Git: C:\Program Files\Git\cmd\git.exe
  • where.exe bash output:

``
C:\Windows\System32\bash.exe
C:\Users\Gower\AppData\Local\Microsoft\WindowsApps\bash.exe
`
(Git Bash at
C:\Program Files\Git\bin\bash.exe` is NOT in system PATH)

View original on GitHub ↗

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