Bug: Claude Code Cursor extension host leaks to 37GB RAM, causes OOM cascade (v2.1.94)

Resolved 💬 2 comments Opened Apr 8, 2026 by LookNoHandsMom Closed May 21, 2026

Environment

  • Extension: anthropic.claude-code-2.1.94-linux-x64 (Cursor marketplace)
  • Cursor: cursor-server commit a80ff7dfcaa45d7750f6e30be457261379c29b00 (remote SSH)
  • Host: Ubuntu 24.04, kernel 6.8.0-107, 48GB RAM, 8GB swap
  • Node: Extension host process (bootstrap-fork --type=extensionHost)

Bug

The Claude Code Cursor extension's extension host process leaked to ~37 GB RSS (78% of system memory) over 2h47m, triggering a system-wide OOM cascade. The kernel OOM killer took out two Chrome processes, and Postgres was next in line (it was invoking the OOM killer itself). Load average hit 290+. This happened twice in one day on the same machine.

The runaway extension host started at 20:38:00 UTC. At 20:38:16 UTC the user launched claude --dangerously-skip-permissions from the integrated terminal. 4 other Cursor windows with Claude Code were open simultaneously — only this one leaked. The other 4 stayed at 0.4–0.6% MEM.

Extension log evidence

From ~/.cursor-server/data/logs/20260407T203707/exthost1/Anthropic.claude-code/Claude VSCode.log:

20:38:06.612 [info] Claude code extension is now active?
20:38:06.612 [info] MCP Server running on port 37577 (localhost only)
20:38:20.344 [info] New WS connection from: /
20:38:20.344 [info] [DiagnosticStreamManager] Started streaming diagnostics
21:29:35.593 [info] diff from .claude/rules/ponder-capabilities.md to ...
21:45:22.134 [info] Closing all diff tabs in the editor... Closed 0 diff tabs.
21:45:23.347 [info] diff result undefined ✻ [Claude Code] ponder-capabilities.md ...
22:17:38.019 [info] [DiagnosticStreamManager] Notifying 1 clients about diagnostics change for 2 files
22:32:36.890 [info] Closing all diff tabs in the editor... Closed 0 diff tabs.
[ ... LOG GOES SILENT — 52 minutes until process killed at 23:24:54 ... ]

Key patterns

  1. Closing all diff tabs... Closed 0 diff tabs appears repeatedly. The cleanup runs but never finds tabs to close — suggesting stale references accumulating in memory that the cleanup can't reach.
  1. diff result undefined at 21:45:23 on the same file that was diffed earlier. If this code path doesn't release allocated resources when the diff fails/returns undefined, it leaks heap.
  1. Log silence for 52 minutes while the process was still running and consuming memory. The most likely explanation: V8 heap exhausted, even the logger can't allocate. The process didn't die because swap kept it alive.
  1. MCP Server on localhost:37577 — WebSocket connections that retain per-message state without bounded backpressure are a classic leak vector.

Impact

| Metric | Value |
|--------|-------|
| Process RSS at kill | ~37 GB (78.2% of 48GB) |
| Process CPU at kill | 75% |
| Process elapsed | 2h 46m 54s |
| Load average | 290.59 / 242.90 / 118.18 |
| OOM kills before intervention | 2 Chrome processes |
| SIGTERM response | Ignored (had to SIGKILL) |
| Memory recovered after kill | 36 GB immediately |

Reproducer hints

  1. Open Cursor IDE remote-SSH'd to a Linux host
  2. Open a project with multiple .claude/rules/*.md files
  3. Run claude --dangerously-skip-permissions in the integrated terminal
  4. Have the agent open/close diff views on rules files repeatedly via MCP
  5. Monitor: ps -o pid,pmem,rss,etime -p <extensionHost-pid>
  6. Wait ~2-3 hours under active use

Not a guaranteed repro — only 1 of 5 concurrent extension hosts leaked. It's a rare runaway condition, not a baseline rate.

Suggested fixes

  1. --max-old-space-size=4096 on the extension host node spawn — 4GB heap is plenty; crash cleanly rather than dragging the host down
  2. Diff-tab lifecycle audit — the "Closed 0 diff tabs" pattern suggests stale references. The undefined diff result path needs to release resources whether the diff succeeded or not
  3. MCP WebSocket backpressure — per-connection caps on queued messages, drop metrics
  4. Memory watchdog — if extension RSS crosses 1GB, write a heap snapshot; at 2GB, warn; at 4GB, self-restart
  5. Liveness signal — if the extension log stops emitting for >5 minutes while the process is running, that's a strong "stuck/leaked" signal

Workarounds we applied (server-side)

  • NODE_OPTIONS=--max-old-space-size=8192 globally (caps all V8 heaps at 8GB)
  • systemd OOM watchdog timer that kills node processes at 8GB RSS
  • Docker/Postgres OOM score protection so databases survive before dev tools

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗