[BUG] SessionStart (and other command-type) hooks fail to execute on Windows — shell resolution drops \bash.exe from Git path
Preflight Checklist
- [x] I have searched existing issues and this hasn't 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's Wrong?
Environment:
Claude Code version: 2.1.197 (Windows Desktop app)
OS: Windows 11 Enterprise 10.0.26200
Git Bash installed at: C:\Program Files\Git\bin\bash.exe
Description:
All "type": "command" hooks fail to execute on Windows, regardless of the hook's actual command content. Confirmed by invoking the CLI binary directly with --output-format stream-json --input-format stream-json and observing hook_started/hook_response events.
Two distinct hooks were registered under SessionStart with matcher: "startup":
A plugin hook running a bash script path (${CLAUDE_PLUGIN_ROOT}/scripts/session-start.sh, shebang #!/bin/bash)
A bare inline diagnostic hook: echo fired >> "C:\Users\...\session-start-diagnostic.log"
Both fail with:
Error occurred while executing hook command: Executable not found in $PATH: "C:\Program Files\Git\bin"
Failed to run: EFTYPE: inappropriate file type or format, uv_spawn
Note the first error's path is missing the trailing \bash.exe — it appears the hook runner enumerates $PATH, finds the C:\Program Files\Git\bin entry (added by the Git for Windows installer), and attempts to spawn that directory string directly as an executable instead of appending \bash.exe.
Proof it's independent of the hook's command content: I changed the diagnostic hook's command to explicitly invoke "C:\Program Files\Git\bin\bash.exe" -c "..." and re-ran the same test — the error output was byte-for-byte identical, indicating the failure happens in shell auto-detection before the specified command is ever reached.
Ruled out:
Stale process/env-var caching (confirmed via full OS reboot — no change)
The Desktop app's --settings {} launch flag overriding file-based hooks (confirmed empty JSON object doesn't override keys per docs)
Missing CLAUDE_CODE_SHELL env var — setting it to C:\Program Files\Git\bin\bash.exe fixed the interactive Bash tool but had zero effect on hook execution, indicating hooks use a separate, unrelated shell-resolution code path
8.3 short path (C:\PROGRA~1\Git\bin\bash.exe) for CLAUDE_CODE_SHELL — no effect
Actual: All command-type hooks fail with the errors above; SessionStart reminders/hooks never take effect for any plugin on this machine.
What Should Happen?
Expected: Command-type hooks execute successfully using an available POSIX shell (Git Bash), consistent with how the interactive Bash tool resolves it.
Error Messages/Logs
Error occurred while executing hook command: Executable not found in $PATH: "C:\Program Files\Git\bin"
Failed to run: EFTYPE: inappropriate file type or format, uv_spawn
Steps to Reproduce
Two distinct hooks were registered under SessionStart with matcher: "startup":
A plugin hook running a bash script path (${CLAUDE_PLUGIN_ROOT}/scripts/session-start.sh, shebang #!/bin/bash)
A bare inline diagnostic hook: echo fired >> "C:\Users\...\session-start-diagnostic.log"
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
2.1.197
Claude Code Version
2.1.197
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_