Hook spawn fails with ENOENT when session CWD is deleted

Resolved 💬 3 comments Opened Mar 20, 2026 by cristoslc Closed Mar 20, 2026

Summary

When the session's working directory is deleted (e.g., after a git worktree removal), all subsequent hook commands fail with:

ENOENT: no such file or directory, posix_spawn '/bin/sh'

The error occurs at the OS level — posix_spawn cannot resolve the process's CWD, so /bin/sh never starts. This means no shell-level mitigation (e.g., cd /valid/path; prefix in the hook command) can help, because the shell process itself cannot be created.

Reproduction

  1. Start a Claude Code session in a git repository
  2. Use EnterWorktree to move the session into a linked worktree
  3. Run an operation that removes that worktree directory (e.g., git worktree remove)
  4. Trigger any hook event (e.g., stop the session)
  5. Observe: ENOENT: no such file or directory, posix_spawn '/bin/sh'

The error repeats on every subsequent hook invocation for the remainder of the session.

Root Cause

child_process.spawn('/bin/sh', ['-c', command]) inherits the process's CWD. When that CWD no longer exists on disk, the kernel rejects the posix_spawn syscall before the shell binary is even loaded.

Suggested Fix

Before spawning hook commands, check whether the current CWD exists and fall back to a valid directory if not:

const cwd = fs.existsSync(process.cwd()) ? process.cwd() : os.homedir();
child_process.spawn('/bin/sh', ['-c', command], { cwd });

This would allow hook commands to execute even when the session's original CWD has been removed. The hook command itself can then cd to whatever directory it needs.

Environment

  • macOS (Darwin 25.3.0)
  • Claude Code 2.1.80
  • Triggered by git worktree removal mid-session

View original on GitHub ↗

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