[BUG] Memory leak: auto-update download Response (2.5 GB) not released after fetch completes
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 ~2.5 GB of memory within 5 minutes of startup. Heap dump analysis pinpoints the root cause to the auto-update mechanism: the HTTP Response object from downloading the update binary is never released after the download completes.
A single Response object fetching the v2.1.72 update binary holds 223 MB directly, and the associated 8,801 ArrayBuffer chunks total 2.21 GB. These are retained by a pending Promise in an async generator, preventing GC from reclaiming any of it.
Heap Dump Analysis
Memory overview (at ~335 seconds uptime):
| Metric | Value |
|--------|-------|
| RSS | 2.54 GB |
| Heap Used | 2.77 GB |
| External Memory | 2.74 GB |
| ArrayBuffers | 2.23 GB |
| Growth Rate | ~27 GB/hour |
Top objects by self size:
| # | Type | Name | Size |
|---|------|------|------|
| 1 | native | Response | 223.16 MB |
| 2 | object | ArrayBuffer (×8801) | 2,211 MB total |
| 3 | native | Blob (×15) | 9.94 MB total |
The leaking Response URL:
https://storage.googleapis.com/claude-code-dist-.../claude-code-releases/2.1.72/linux-x64/claude
Retention chain:
(root)
└─ GlobalObject
└─ InternalModuleRegistry
└─ Object (http module exports)
└─ JSLexicalEnvironment (bundled code, 195 KB)
└─ Generator → pending Promise (never resolves)
└─ IncomingMessage
└─ FetchAPI → Response (223 MB)
└─ ReadableStream body → ArrayBuffers (2.2 GB)
The key issue: an async generator holds a reference to the Response via a JSLexicalEnvironment closure. The generator is suspended on a pending Promise that never resolves, so the entire response body (streamed into thousands of ArrayBuffer chunks) is permanently retained.
What Should Happen?
After the auto-update binary is downloaded and written to disk, the Response object and all associated ArrayBuffer chunks should be released (e.g., by calling response.body.cancel(), nullifying references, or ensuring the consuming async generator completes/returns).
Steps to Reproduce
- Open Claude Code v2.1.71 on Linux (WSL2 Ubuntu) when a newer version (2.1.72) is available
- Wait ~5 minutes
- Observe memory usage climbing to 2.5+ GB
- Take a heap dump (
/heapdump) and observe theResponse→ArrayBufferretention chain
Error Messages/Logs
Diagnostics JSON from /heapdump:
{
"memoryUsage": {
"heapUsed": 2774169282,
"heapTotal": 46575616,
"external": 2735764610,
"arrayBuffers": 2338137054,
"rss": 2663563264
},
"memoryGrowthRate": {
"bytesPerSecond": 7946604.73,
"mbPerHour": 27282.50
},
"analysis": {
"potentialLeaks": ["High memory growth rate: 27282.5 MB/hour"],
"recommendation": "WARNING: 1 potential leak indicator(s) found."
}
}
Claude Model
Opus
Is this a regression?
I don't know
Claude Code Version
2.1.71
Platform
Anthropic API
Operating System
Linux (WSL2 Ubuntu on Windows, kernel 6.6.87.2-microsoft-standard-WSL2)
Terminal/Shell
Bash
Additional Information
- Node.js version: v24.3.0
- The heap snapshot file is 34 MB and available upon request
- This likely explains many of the open memory leak reports (#31621, #25023, #24827, #17615, etc.) — they may all share this same root cause
- Suggested fix: ensure the update download response stream is properly consumed and closed, and that no async generator keeps a dangling reference to the Response object
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗