[BUG] VSCode extension: fd leak from session transcript scanning causes "Error: spawn EBADF" after hours of uptime

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 29, 2026

Description

The VSCode extension's host process leaks file descriptors for Claude session transcripts. On every periodic rescan of ~/.claude/projects/, the extension opens every .jsonl transcript in every project directory and never closes the handles. After a few hours of uptime the extension host holds thousands of fds, and from that point every attempt to spawn the bundled claude binary fails with Error: spawn EBADF. Both new session launches and the claude auth status probe in refreshCliAuthStatus fail. Already-running sessions keep working. Restarting VSCode or the extension host clears the fd table and everything works again until the leak reaccumulates.

Environment

  • Claude Code VSCode extension: 2.1.220 (current marketplace latest, bundled native binary)
  • macOS, Apple Silicon
  • A few hundred session transcripts on disk in ~/.claude/projects/ (ordinary daily-driver usage)

Evidence

Measured on a live extension host a few hours after start, with multiple Claude panes open:

  • 4,349 open fds total, of which 4,281 were regular files and ~4,200 were transcripts under ~/.claude/projects/ (lsof -p <exthost pid>). Highest fd number in use: 4313.
  • Every transcript file was held open exactly 25 times, matching 25 scans since the extension host started (roughly one scan every 7 to 8 minutes). Per-directory totals match file count on disk times scan count; for example, a project directory with 82 transcripts on disk accounted for 1,991 open fds (82 x 25, minus files created after the early scans).
  • Zero EMFILE anywhere in the logs. The failure is EBADF at spawn time, consistent with macOS posix_spawn fd-table setup failing once the parent's fd numbers are in the thousands, rather than classic fd-count exhaustion.
  • Failure onset correlates with uptime, not with any specific action: in one app run the first EBADF appeared roughly five hours after the window opened, and failures then recurred until restart. Short-lived windows never hit it.

Log excerpt (Claude VSCode.log, timestamps and channel ids omitted):

[info] Launching Claude on channel: <id>
[info] Spawning Claude with SDK query function - cwd: /Users/<user>, version: 2.1.220
[error] Error spawning Claude (on channel <id>): Error: spawn EBADF
[error] Failed to load config cache: Error: spawn EBADF
[error] Error processing client request: Error: spawn EBADF

Stack trace (exthost.log):

Error: spawn EBADF
    at ChildProcess.spawn (node:internal/child_process:441:11)
    at Object.spawn (node:child_process:829:9)
    at extension.js:335:19611
    at go.refreshCliAuthStatus (extension.js:335:19584)
    at go.getAuthStatus (extension.js:335:19208)
    at go.processRequest (extension.js:335:27923)

Reproduction

  1. Accumulate a few hundred session transcripts in ~/.claude/projects/ (normal daily use gets there quickly).
  2. Open a VSCode window with the Claude Code extension and use a session or two.
  3. Watch lsof -p <extension host pid> | grep -c "/.claude/projects/" climb by (number of transcripts on disk) every few minutes and never go down.
  4. After a few hours, launching any new Claude pane fails immediately with spawn EBADF until the extension host restarts.

Notes

  • Possibly related to #62735 (closed as stale). That report ruled out fd exhaustion on a fresh process; this one is specifically the extension host accumulating transcript fds over hours, which explains the "works after restart, breaks after ~30+ minutes" pattern many users describe.
  • Workarounds that follow from the root cause: "Developer: Restart Extension Host" resets the fd table without a full VSCode restart; reducing transcript retention (cleanupPeriodDays) slows the leak proportionally.

View original on GitHub ↗