[BUG] File Descriptor Leak in FSWatcher for pending-claude-sessions.json Causes EINVAL Crash
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code leaks file descriptors when watching pending-claude-sessions.json during atomic write operations. The FSWatcher attaches to temporary .tmp files that are immediately renamed/deleted, leaving orphaned file handles. These accumulate over time (42,000+ in a single session) and eventually cause unhandled promise rejection crashes with EINVAL: invalid argument, watch.
What Should Happen?
- File watchers should be properly closed when the watched file is renamed or deleted
- Atomic write operations should not leave orphaned file descriptors
- The FSWatcher should watch the final file path, not the intermediate .tmp file
- EINVAL errors should be handled gracefully instead of crashing the session
Error Messages/Logs
This error originated either by throwing inside of an async function without a catch block,
or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
Error: EINVAL: invalid argument, watch '/home/user/.claude/pending-claude-sessions.json.tmp'
at watch (unknown)
at new FSWatcher (node:fs:30:31)
at watch (node:fs:300:23)
at tMI (/$bunfs/root/claude:389:6265)
at Tv0 (/$bunfs/root/claude:389:11478)
at _watchWithNodeFs (/$bunfs/root/claude:389:6746)
at _handleFile (/$bunfs/root/claude:389:7489)
at _addToNodeFs (/$bunfs/root/claude:389:10516)
at processTicksAndRejections (native:7:39)
Evidence of file descriptor leak (lsof output showing 42,777 orphaned FDs):
claude 2487674 user 19r REG 8,48 0 181658 .claude/pending-claude-sessions.json.tmp (deleted)
claude 2487674 user 21r REG 8,48 0 181654 .claude/pending-claude-sessions.json.tmp (deleted)
claude 2487674 user 24r REG 8,48 0 181640 .claude/pending-claude-sessions.json.tmp (deleted)
... (42,000+ more entries all marked "(deleted)")
Steps to Reproduce
- Run Claude Code with claude --dangerously-skip-permissions
- Use the session normally for 10-30+ minutes
- Monitor file descriptors with: lsof 2>/dev/null | grep "claude.*pending-claude.*deleted" | wc -l
- Observe orphaned FD count growing continuously (~1,200 leaked FDs per minute)
- Eventually session crashes with EINVAL error
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.0.76 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information
Root cause analysis:
- Claude uses atomic writes (write to .tmp, then rename to final file)
- FSWatcher incorrectly attaches to the .tmp file
- When .tmp is renamed/deleted, the file descriptor is NOT closed
- Each atomic write cycle creates another orphaned FD
- Operations on orphaned FDs eventually throw EINVAL
Impact:
- Session crashes from unhandled promise rejections
- Memory/kernel resource consumption from leaked FDs
- Affects users running multiple concurrent sessions (valid use case)
- Makes long-running sessions unstable
Related issues:
- #7624 (ENOSPC from settings file watcher - similar FSWatcher mechanism)
- #6598 (EINVAL write error - different root cause but same error code)
- #10505 (Memory leak in write loop - similar resource leak pattern)
Suggested fix:
- Watch the directory or final file path, not the .tmp intermediate
- Properly close file watchers when watched file is renamed/deleted
- Handle EINVAL gracefully instead of crashing
Found 3 possible duplicate issues:
- https://github.com/anthropics/claude-code/issues/15073
- https://github.com/anthropics/claude-code/issues/14438
- https://github.com/anthropics/claude-code/issues/15068
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with Claude Code
This issue has been automatically closed as a duplicate of #15073.
If this is incorrect, please re-open this issue or create a new one.
🤖 Generated with Claude Code
This issue was actually rectified. There was a problem with custom scripts in my Tmux that was referencing Claude Code too frequently, and it had been imported cross-platform incorrectly. So this one's on me, sorry.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.