[BUG] Windows: Hook .sh auto-detection resolves to WSL bash.exe instead of Git Bash when WSL is installed
Bug Description
On Windows systems with WSL installed, Claude Code's hook execution resolves bash to WSL's C:\Windows\System32\bash.exe instead of Git Bash's bash.exe, causing all plugin hooks using .sh scripts to fail.
Claude Code correctly detects the right bash path at startup:
Using bash path: "C:\Program Files\Git\bin\bash.exe"
But when executing hook commands, it uses generic bash which the Windows PATH resolves to WSL's bash.exe:
C:\Windows\System32\bash.exe → WSL bash → fails
Reproduction Steps
- Install Git for Windows (provides Git Bash)
- Install Docker Desktop (installs WSL automatically) or have WSL installed without a configured distro
- Install any Claude Code plugin that uses
.shhooks (e.g.,explanatory-output-style,learning-output-style,ralph-wiggum) - Start a Claude Code session
Expected Behavior
Hooks execute successfully using Git Bash.
Actual Behavior
Hook execution fails with:
<3>WSL (2) ERROR: CreateProcessCommon:559: execvpe /bin/bash failed : No such file or directory
<3>WSL (2) ERROR: CreateProcessCommon:562: Create process not expected to return
Or silently fails/produces no output.
Root Cause
The Windows PATH typically resolves bash in this order:
C:\Windows\System32\bash.exe(WSL - takes precedence)C:\Program Files\Git\bin\bash.exe(Git Bash)
When a hook command is ${CLAUDE_PLUGIN_ROOT}/hooks-handlers/session-start.sh, Claude Code detects the .sh extension and auto-prepends bash, which resolves to WSL bash instead of Git Bash.
Affected Plugins
All 3 official plugins with .sh hooks:
explanatory-output-style—hooks-handlers/session-start.shlearning-output-style—hooks-handlers/session-start.shralph-wiggum—hooks/stop-hook.sh
Environment
- OS: Windows 10/11 with WSL installed
- Claude Code: 2.x (tested on 2.1.x)
- Shell: Git Bash
- Extremely common scenario: Docker Desktop automatically installs WSL
Proposed Fix
Add cross-platform .cmd polyglot wrappers that:
- On Windows (cmd.exe): explicitly invoke Git Bash at its standard path
- On Unix/macOS: pass through to the
.shscript natively
This approach requires no changes to the core binary and fixes all affected plugins.
Workaround
Manually edit each plugin's hooks.json to use the explicit Git Bash path:
{
"command": "\"C:/Program Files/Git/usr/bin/bash.exe\" ${CLAUDE_PLUGIN_ROOT}/hooks-handlers/session-start.sh"
}
Note: Plugin updates overwrite this fix.
Related Issues
- #22700 — bash not in PATH (different root cause but same symptom area)
- #21468 — superpowers plugin fails on Windows
- #21878 — Windows hook execution issues
- PR #19084 — ralph-wiggum
.cmdwrapper (narrow scope, same approach)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗