Stop hooks fail with 'spawn /bin/sh ENOENT' on macOS

Resolved 💬 2 comments Opened Jan 9, 2026 by Morriz Closed Jan 9, 2026

Description

Stop hooks fail to execute with the error spawn /bin/sh ENOENT even though /bin/sh exists and is accessible.

Environment

  • Claude Code version: 2.1.1
  • OS: macOS Darwin 25.1.0
  • Shell: /bin/sh exists at -rwxr-xr-x 1 root wheel 101232 /bin/sh

Steps to Reproduce

  1. Configure Stop hooks in ~/.claude/settings.json:
{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/python /path/to/script.py stop"
          }
        ]
      }
    ]
  }
}
  1. Also have a plugin with Stop hooks enabled (e.g., ralph-loop plugin)
  1. Run Claude Code and let it complete a response (trigger Stop event)

Expected Behavior

Stop hooks should execute successfully.

Actual Behavior

Both Stop hooks fail with:

Ran 2 stop hooks
  ⎿  Stop hook error: Failed with non-blocking status code: Error occurred while executing hook command: spawn /bin/sh ENOENT
  ⎿  Stop hook error: Failed with non-blocking status code: Error occurred while executing hook command: spawn /bin/sh ENOENT

Analysis

  • /bin/sh exists and is executable
  • Hook scripts are executable and have correct permissions
  • The error occurs for ALL Stop hooks (both user-configured and plugin hooks)
  • This suggests the issue is in the hook execution layer, not the individual hooks
  • Node.js child_process.spawn() appears unable to find the shell in the execution environment

Workaround

Currently disabling hooks that use the Stop event.

Additional Context

The hooks work fine for other events (SessionStart, SubagentStop, etc.) based on logs. The issue appears specific to the Stop hook execution context.

View original on GitHub ↗

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