Linux: hook blocked reading stdin (pipe kept open, no EOF) wedges the session for hours; declared hook timeout not enforced (2.1.246)

Status Closed — not planned
Reported on v2.1.246
Maintainer reply None cached
Activity 1 comment · opened Aug 29, 2026 · closed Aug 29, 2026

Environment

  • Claude Code 2.1.246 (version of the wedged process, taken from the session transcript; client updated to 2.1.251 during triage — CHANGELOG through 2.1.250 lists no related fix)
  • Linux x86_64 (Debian-based), zsh login shell
  • Hooks declared in ~/.claude/settings.json, each entry with an explicit timeout field (5–15s)

What happened (twice in one day, same session)

  1. A turn ended while two Bash run_in_background tasks were still running.
  2. Their completion notifications were never delivered. The session froze, showing the statusMessage of one of our hooks in the spinner. The background tasks themselves kept running and finished normally.
  3. First freeze lasted ~8 hours and ended only when the user interrupted; the second (same day, ~1.5h) ended with a process restart. After the interrupt/restart, the pending task notifications arrived immediately.

Measured mechanism (hook side)

The hook script read its stdin payload with an unbounded read (dd bs=1048577 count=1; a sibling hook used payload=$(cat)). Measured with process substitution so only the script is timed:

$ time sh hook.sh < <(sleep 6)     # pipe open, no EOF
6.003s                             # blocks exactly as long as the pipe stays open
$ echo '{"hook_event_name":"PreToolUse"}' | time sh hook.sh
0.052s                             # normal delivery with EOF is instant

So during the freeze the client kept the hook's stdin pipe open without EOF for hours — scaled from the 6s probe, this fully explains the 8h wedge.

Declared timeout not enforced

The wedged hook entry declared "timeout": 5. The hook process was not terminated (8h > 5s). This matches #87289 (timeout not applied while hook blocks reading stdin) and #85250 (timeout not enforced parent-side); the pipe-kept-open behavior matches #78756. All three are currently Windows-labeled or unlabeled — this is a Linux data point with a hard measurement.

Mitigation that works (and the ask)

Wrapping the stdin read inside the script (timeout 2 dd …) ends the hang class: verified 2.043s with a 30s-open pipe, normal path unchanged.

Ask: (1) close the hook's stdin after writing the payload on every code path, including the end-of-turn/notification-delivery path; (2) enforce the declared per-hook timeout parent-side even while the hook blocks on stdin.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗