Hooks fail with posix_spawn ENOENT when session cwd is deleted; request fallback cwd before spawning hooks

Open 💬 4 comments Opened Jun 4, 2026 by Nickcom4

Summary

When Claude Code spawns a hook, it appears to use posix_spawn('/bin/sh', ..., {cwd: <session_cwd>}). If <session_cwd> no longer exists at spawn time (common when a session was started inside a git worktree that has since been removed, or any directory deleted out from under a live session), the spawn fails with ENOENT before the hook body runs. Every hook for that event then dies identically, silently disabling the hook layer for the rest of the session.

Repro

  1. Start a session with cwd inside a directory that can be deleted (e.g. a git worktree).
  2. Delete that directory while the session is live (e.g. a worktree-cleanup step, a branch reaper, a concurrent process).
  3. Trigger any hook event (Stop, PreToolUse, etc.).

Observed: posix_spawn '/bin/sh' ... ENOENT; the hook never executes.

Why user-side mitigation cannot fully fix it

A common workaround is to cd "$HOME" at the top of each hook body when the cwd is gone. This cannot help here: the failure is at posix_spawn time, before the hook body (the /bin/sh invocation) starts, so no in-body recovery code ever runs. The only complete fix is in the harness: resolve a guaranteed-existing fallback cwd (e.g. $HOME, or the repo root, or the directory the Claude Code binary was launched from) before posix_spawn-ing a hook when the recorded session cwd no longer exists.

Request

Before spawning a hook, if the recorded session cwd does not exist, fall back to a known-good directory ($HOME or launch dir) rather than passing a deleted path to posix_spawn. This keeps the hook layer alive across directory-deletion races instead of silently disabling it.

Context

Witnessed repeatedly with worktree-based workflows where cleanup automation removes the worktree a session is sitting in; all Stop hooks for the session failed identically with the recover-cwd lib already sourced at their top (which, per the above, cannot help). Filing as the upstream half of a tracked downstream issue.

View original on GitHub ↗

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