Skip to content

Windows: SessionStart hooks that invoke bash fail (exit 127, bash: command not found) #63828

Description

@KLPTechSys

Environment

  • Claude Code v2.1.157 (CLI)
  • Windows 11 Pro (10.0.26200)
  • Git for Windows (user install): C:\Users\<user>\AppData\Local\Programs\Git\usr\bin\bash.exe (GNU bash 5.2.37 msys)
  • Repro plugin: official semgrep plugin v0.5.3 (SessionStart hook check_version.sh)

Summary

On Windows, any hook command whose first token resolves to bash fails with exit 127 and /usr/bin/bash: line 1: bash: command not found. The hook's target script never executes. Hook commands that are a bare, PATH-resolvable Windows executable work fine. This makes the official semgrep plugin throw a SessionStart error on every startup/resume/clear/compact.

Steps to reproduce

  1. On Windows with Git Bash, enable the official semgrep plugin (v0.5.3).
  2. Start/resume/clear a session. Its hooks.json includes:
    { "type": "command", "command": "/usr/bin/bash \"${CLAUDE_PLUGIN_ROOT}/scripts/check_version.sh\"" }
  3. Observe a SessionStart:startup hook error every time.

Expected: the hook runs check_version.sh and exits 0.
Actual: exit 127, stderr /usr/bin/bash: line 1: bash: command not found. The script body never runs.

Decisive evidence

I tested three ways of spelling the bash invocation via temporary SessionStart hooks; all fail identically, while a bare executable in the same hook set succeeds:

Hook command Result
/usr/bin/bash "<script>" (semgrep's form) exit 127, bash: command not found
bash "<script>" (bare) exit 127, identical
"C:\Users\<user>\AppData\Local\Programs\Git\usr\bin\bash.exe" "<script>" (full Windows path) exit 127, identical
semgrep mcp -k inject-secure-defaults (bare exe) exit 0

Transcript hook records (attachment.type: hook_non_blocking_error):

exitCode: 127
command: /usr/bin/bash "${CLAUDE_PLUGIN_ROOT}/scripts/check_version.sh"
stderr:  Failed with non-blocking status code: /usr/bin/bash: line 1: bash: command not found

A probe script that simply writes a file produced no file — confirming failure is upstream of the target script, at the bash invocation itself.

Analysis

Claude Code appears to wrap every hook command in Git Bash (/usr/bin/bash -c "<command>"). When <command> itself invokes bash (a nested/second bash), that nested invocation cannot be resolved — note the error reports the failed program as bare bash regardless of whether the command specified /usr/bin/bash or a full Windows path, suggesting the inner program token is normalized/mangled to bash and then not found on the wrapper's PATH. A bare exe like semgrep resolves via the Windows PATH and works, so it is specifically bash-invoking hook commands that break. (This is a regression in behavior: an earlier workaround of using absolute /usr/bin/bash previously worked on this box and no longer does.)

Impact

  • The official semgrep plugin emits a SessionStart error on every session event on Windows.
  • Any plugin/user hook that shells out to a script via bash is broken on Windows. Non-blocking, but persistent and confusing.

Workaround

Remove the bash-invoking hook from the plugin's hooks.json (lives in the version-numbered plugin cache, so it's overwritten on plugin update). There is no per-hook disable in settings, so this recurs after updates.

Suggested fix

When executing hook commands on Windows, ensure the wrapper's environment can resolve a nested bash invocation (preserve bash/Git usr/bin on the hook PATH, or don't normalize the inner interpreter token), so command: "/usr/bin/bash <script>" works as plugin authors expect.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:hooksbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:windowsIssue specifically occurs on Windows

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions