Terminal hard-locks when Bash tool executes piped node | node with readFileSync('/dev/stdin')
Description
Claude Code terminal hard-locks (no ctrl+c, no interrupt, must force-quit process) when the Bash tool executes commands that pipe one Node.js process into another where the reader uses readFileSync('/dev/stdin').
Repro
Any command in this shape via the Bash tool:
node some-cli.js --json 2>/dev/null | node -e "console.log(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')))"
Locked 3/3 times during a single session. The command runs fine in a raw terminal and also works when wrapped in timeout 10 bash -c '...'.
Expected
Command executes normally and returns output.
Actual
Terminal freezes completely. No ctrl+c. No interrupt. Must force-quit.
Environment
- macOS Darwin 25.2.0
- Node.js >= 22
- Claude Code (Opus 4.6)
Hypothesis
Claude Code's child process stdio management doesn't properly propagate pipe close/EOF between the two sides of A | B. The right side's readFileSync('/dev/stdin') blocks forever waiting for EOF. This locks the child bash process, which locks Claude Code, which locks the terminal.
Evidence: wrapping in timeout bash -c '...' works — likely because timeout creates an independent process group with clean pipe lifecycle management.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗