[Bug] statusline.js causes infinite loop and EBADF error in Claude Code
🐛 Bug Report
Summary
When statusLine configuration is set in ~/.claude/settings.json, Claude Code enters an infinite loop and crashes with an EBADF error.
Environment
- Claude Code Version: 1.0.85+
- Node Version: v24.5.0
- Platform: macOS (Darwin)
- Installation: via nodebrew
Configuration
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.js"
}
}
Error Output
node:internal/child_process:421
throw new ErrnoException(err, 'spawn');
^
Error: spawn EBADF
at ChildProcess.spawn (node:internal/child_process:421:11)
at spawn (node:child_process:795:9)
at file:///Users/a14073/.nodebrew/node/v24.5.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:165:2705
at TA0 (file:///Users/a14073/.nodebrew/node/v24.5.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:165:3200)
at file:///Users/a14073/.nodebrew/node/v24.5.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:165:3433
at Array.forEach (<anonymous>)
at ChildProcess.W (file:///Users/a14073/.nodebrew/node/v24.5.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:165:3368)
at ChildProcess.emit (node:events:507:28)
at ChildProcess.emit (node:domain:489:12)
at maybeClose (node:internal/child_process:1101:16) {
errno: -9,
code: 'EBADF',
syscall: 'spawn'
}
Node.js v24.5.0
Analysis of the Problem
The EBADF (Bad File Descriptor) error typically indicates one of the following issues:
- File descriptor exhaustion: The statusline.js script spawns multiple child processes via
execSync()for git commands (lines 426-436, 626-641, etc.). If these are called frequently without proper cleanup, file descriptors may be exhausted.
- Recursive spawn issue: The error stack trace shows the crash occurs during
ChildProcess.spawn, suggesting a possible recursive spawning issue where Claude Code repeatedly attempts to execute the statusline command.
- Resource leak in child processes: The statusline.js uses
execSync()with various git commands. If these commands fail or timeout repeatedly, they might leave zombie processes or unclosed file descriptors.
Potential Root Causes
Looking at the statusline.js implementation:
- Multiple execSync calls: The script makes numerous synchronous shell calls:
- Git status checks (lines 626-641)
- Git branch information (line 632)
- Git status porcelain v2 (line 638)
- Claude version detection (line 433)
- File reading operations: Multiple file read operations for:
- Transcript files (line 256)
- Difficulty files (lines 324-336)
- Package.json for version detection (lines 416-429)
- Opus4 usage tracking (line 459)
- Stream handling: The script uses readline streams (lines 257-290, 543-620) which might not be properly closed in error scenarios.
Reproduction Steps
- Set the statusLine configuration in
~/.claude/settings.jsonas shown above - Start Claude Code
- Claude Code enters an infinite loop and crashes with EBADF error
Expected Behavior
The statusline should display properly without causing Claude Code to crash.
Actual Behavior
Claude Code enters an infinite loop and terminates with an EBADF error.
Possible Solutions
- Add proper error handling and resource cleanup:
- Ensure all streams are properly closed
- Add try-catch blocks around execSync calls
- Implement timeout handling for git commands
- Reduce subprocess spawning:
- Cache git information for a short period
- Batch git commands where possible
- Use native Node.js git libraries instead of spawning processes
- Implement rate limiting:
- Add a minimum interval between statusline updates
- Implement debouncing for rapid calls
- File descriptor management:
- Explicitly close file descriptors after use
- Monitor and limit concurrent subprocess spawns
Workaround
Remove or comment out the statusLine configuration from ~/.claude/settings.json until the issue is resolved.
Additional Context
The statusline.js script is a custom implementation that displays various information including:
- Git branch and status
- Token usage tracking
- Task difficulty indicators
- Opus4 model usage tracking
The script works independently when tested outside of Claude Code, suggesting the issue is in the interaction between Claude Code's spawning mechanism and the script's subprocess calls.
Labels
- bug
- critical
- statusline
- resource-leak
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗