100% CPU spin after terminal disconnect - stdio revocation not handled
Resolved 💬 3 comments Opened Feb 1, 2026 by krushr1 Closed Feb 4, 2026
Bug Description
Claude Code spins at 100% CPU indefinitely after the parent terminal is closed, instead of gracefully exiting.
Environment
- macOS (Apple Silicon)
- Claude Code CLI
- Node.js v22.16.0
Reproduction
- Start a Claude Code session in a terminal
- Close the terminal window (or let terminal crash)
- Observe orphaned
claudeprocess at 100% CPU withPPID=1
Evidence
Process stuck for nearly 3 hours at 100% CPU:
Process Name % CPU CPU Time PID PPID
claude 100.0 2:52:52.21 19090 1
lsof -p 19090 shows revoked file descriptors:
node 19090 0 (revoked) ← stdin
node 19090 1 (revoked) ← stdout
node 19090 2 (revoked) ← stderr
node 19090 14 (revoked) ← MCP pipe
node 19090 18 (revoked) ← MCP pipe
node 19090 19 (revoked) ← MCP pipe
Root Cause
When the terminal closes, macOS revokes the stdio file descriptors. The Node.js process continues running (orphaned to launchd) but every read/write to stdin/stdout returns immediately with EBADF/EPIPE. Without backoff or detection, this causes a tight loop at 100% CPU.
Suggested Fix
process.stdin.on('error', (err) => {
if (err.code === 'EBADF' || err.code === 'EPIPE') {
process.exit(0); // Graceful exit on terminal disconnect
}
});
process.stdout.on('error', (err) => {
if (err.code === 'EPIPE') {
process.exit(0);
}
});
// Or handle SIGHUP properly
process.on('SIGHUP', () => {
// Cleanup and exit
process.exit(0);
});
Impact
- Wastes CPU resources indefinitely
- Can accumulate multiple zombie processes over time
- Battery drain on laptops
- Requires manual
killto clean up
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗