-
Notifications
You must be signed in to change notification settings - Fork 700
Closed
Description
I encountered this issue and Claude proposed the following fix. DISCLAIMER: I am not knowledgeable enough to know whether this is the best solution but I wanted to raise awareness so it can be addressed.
Bug Report: stop-hook.ts fails with "spawn /bin/sh ENOENT" error
Description
The stop-hook.ts file fails with the error spawn /bin/sh ENOENT when Claude Code executes the Stop hook in certain contexts.
Root Cause
Lines 524-527 in hooks/stop-hook.ts use Node.js child_process.execSync() to execute shell commands for setting terminal tab titles:
const { execSync } = await import('child_process');
execSync(`printf '\\033]0;${escapedTitle}\\007' >&2`);
execSync(`printf '\\033]2;${escapedTitle}\\007' >&2`);
execSync(`printf '\\033]30;${escapedTitle}\\007' >&2`);This approach requires spawning a /bin/sh shell process, which can fail in the execution context where Claude Code runs hooks.
Error Message
⏺ Stop [bun ${PAI_DIR}/hooks/stop-hook.ts] failed with non-blocking status code 1: Error
occurred while executing hook command: spawn /bin/sh ENOENT
Impact
- Hook fails completely when shell spawn fails
- Voice notifications and tab title updates don't work
- Users see error messages on every Claude Code session stop
Proposed Solution
Replace execSync() calls with direct process.stderr.write() using ANSI escape sequences. This approach is:
- Already used elsewhere in the same file (lines 105-130) for the same purpose
- More reliable (no shell process spawning required)
- More performant (no process spawning overhead)
- Functionally identical
Environment
- Claude Code version: 2.0.8
- Bun version: 1.2.23
- macOS Darwin 24.5.0
Metadata
Metadata
Assignees
Labels
No labels