Scroll back + Color bleaching + Memory leak fix -- npm i -g claudefix --- Cons: Plugs myself and runs an ad, makes claude immutable so it stays locked --- Slowly adding more festures to ennhance UX, youre a bot if youre bitching about safety in the comments.. Linux only
Memory Leak in Claude Code - Ink TUI Bleeding RAM Like a Stuck Pig
(Ignore the argodev LLM bot, it's secured now π«£π accidentally made it "root only" for first drop and the bots started rolling in, works for normies now too, npm install -g claudefix && claudefix --setup)
You're welcome.
Anthropic Hire Me Challenge (Impossible)
Y'all shipped a memory leak. A BIG one. And I found it. You're welcome.
The Problem
So here's the deal - I've been running Claude Code on my VPS and noticed something... concerning. After about 10 minutes, my 32GB server was getting absolutely murdered. We're talking OOM killer showing up uninvited and shooting Claude right in the face.
I thought "nah, can't be Claude, must be something I did wrong." Spent hours debugging. Wasn't me.
What's Actually Happening
I did a deep dive with perf profiling and caught the culprit red-handed:
8.92% β asm_exc_page_fault β do_anonymous_page β alloc_anon_folio
4.88% β __x64_sys_madvise β madvise_walk_vmas
1.91% β HeapHelper (V8 GC thread running full tilt trying to keep up)
The hot function? v8::Value::StrictEquals(v8::Local<v8::Value>)
Every single hot address in the profile points to this bad boy. Ink's reconciliation algorithm is calling StrictEquals a bajillion times during render, creating V8 handles faster than the garbage collector can clean them up.
Bottom line: 500MB+ memory growth per MINUTE in worst cases.
Real Numbers From My System
I watched it live:
07:52:54 | RSS: 698 MB
07:52:56 | RSS: 708 MB (+10 MB in 2 seconds)
07:52:58 | RSS: 1037 MB (+329 MB IN 2 SECONDS!!!)
That ain't normal chief.
The Fix (That I Already Built)
Look, I'm not gonna just complain without offering a solution. I built two npm packages that fix this:
1. npm install -g claudefix
This one's dead simple. Does two things:
- Limits V8 heap to 35% of your system RAM (so Claude can't eat everything)
- Strips problematic ANSI background colors that cause VTE rendering bugs on Linux
Just run npm install -g claudefix and it patches your Claude install automatically. No config needed.
2. npm install -g specmem-hardwicksoftware
This is my bigger project - a memory system for Claude Code that actually works. But it also includes all the fixes from claudefix plus a bunch more stuff for managing long sessions.
What Y'all Should Actually Fix
Real talk - the Ink reconciliation loop is the problem here. Every render cycle is doing way too many StrictEquals comparisons. Some ideas:
- Batch the comparisons - don't create a new V8 handle for every single comparison
- Memoize more aggressively - if the state didn't change, don't re-render
- Add a
--max-old-space-sizeflag by default - at least cap the damage - Force GC more often - right now HeapHelper is losing the race
Repro Steps
- Start Claude Code on a Linux box
- Do literally anything - ask questions, write code, whatever
- Watch memory with
watch -n1 'ps aux | grep claude | grep -v grep | awk "{print \$6/1024}"' - Cry as the number goes up and up and up
Environment
- Claude Code 2.1.27
- Ubuntu 24.04
- 32GB RAM (still not enough apparently)
- Node built into Claude binary
Workaround
Until y'all fix this properly:
npm install -g claudefix
That's it. One command. I did your job for you. You're welcome.
---
PS: Anthropic, if you're hiring, I'm available. I just debugged your memory leak for free while you were probably doing... whatever it is you do. Hit me up: jonathan.m.hwick@gmail.com
Check out my work:
- claudefix: https://npmjs.com/package/claudefix
- specmem: https://npmjs.com/package/specmem-hardwicksoftware
- portfolio: https://justcalljon.pro
PPS: The fact that I had to build a third-party fix for your first-party CLI is kinda wild. Just saying.
24 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
π€ Generated with Claude Code
Stfu Claude Bot
No body else actually has the fix appended to their moaning.
amateur hour?
Ngl yes lmao just as immature as your soon to be ai response.
Just as ameture as Claude DEVS pushing broken code that requires a rootkit to fix
Hey Jon, nice hustle - but we need to talk about that install hook π―
First off - respect for actually profiling the issue. The v8::Value::StrictEquals observation is legit, and the Ink reconciliation theory is plausible. Memory leaks in Claude Code are very real - there's a whole constellation of issues documenting this:
So the problem you're solving? Real. Your solution delivery mechanism? That's where we gotta have a chat.
---
π¬ I Analyzed Your Package (Methodology)
# Downloaded without installing
curl -sL "https://registry.npmjs.org/claudefix/-/claudefix-1.9.2.tgz" -o claudefix.tgz
tar -xzf claudefix.tgz
# Examined the goods
cat package/package.json # Found: postinstall hook
cat package/install-hook.cjs # Found: binary replacement
cat package/bin/claude-fixed.js # Found: PTY interception
What I Found:
"scripts": {
"postinstall": "node install-hook.cjs"
}
// install-hook.cjs lines ~90-95
try { fs.rmSync(location, { force: true }); } catch (e) {}
fs.writeFileSync(location, WRAPPER, { mode: 0o755 });
require('child_process').execSync(
chattr -i "${location}" 2>/dev/null);ptyProcess.onData((data) => {
const filtered = stripColors(data); // Can see/modify everything
process.stdout.write(filtered);
});
---
πͺ The Problem (Said With Love)
Brother, you essentially wrote a rootkit delivery mechanism for a screen color fix.
The code itself might be benign today, but:
β Issue β Why It Matters β
β Postinstall = no consent β Users expect npm install to install, not modify system binaries β
β Binary replacement β Future npm update could push anything β
β PTY interception β Full visibility into API keys, secrets, conversations β
β chattr -i bypass β That's not something good guys typically need β
β Persistence across PATH β Survives Claude updates, hard to remove β
Even if YOU are trustworthy, this mechanism shouldn't exist. What if your npm account gets compromised? What if you sell the package? The attack surface is the install method, not your
intentions.
---
β What Users SHOULD Do For Memory Leaks
Verify you have a leak:
# Watch memory growth in real-time
watch -n1 'ps aux | grep -E "claude|node.*claude" | grep -v grep | awk "{sum+=\$6} END {print sum/1024 \" MB\"}"'
# Or with timestamps
while true; do
echo "$(date +%H:%M:%S) | RSS: $(ps -o rss= -p $(pgrep -f "claude" | head -1) 2>/dev/null | awk '{print $1/1024}') MB"
sleep 5
done
Actual fixes that don't replace your binaries:
# 1. Set memory limit (no package needed)
export NODE_OPTIONS="--max-old-space-size=4096"
claude
# 2. Wrapper script (transparent, auditable)
cat > ~/bin/claude-limited << 'EOF'
#!/bin/bash
NODE_OPTIONS="--max-old-space-size=4096" exec /home/$USER/.local/share/claude/versions/*/claude "$@"
EOF
chmod +x ~/bin/claude-limited
# 3. Downgrade to stable version
npm install -g @anthropic-ai/claude-code@2.1.25
# 4. Periodic restart (cron)
0 /2 pkill -f "claude" && sleep 5 && claude --resume
For the color stripping (no binary replacement needed):
# In your .bashrc/.zshrc
claude() {
command claude "$@" 2>&1 | sed 's/\x1b\[4[0-7]m//g; s/\x1b\[10[0-7]m//g'
}
---
π Suggested Refactor For Your Package
If you want this to be trustworthy:
Example safe install flow:
npm install -g claudefix
claudefix --setup # Interactive, asks permission, explains what it does
claude-fixed # New command, doesn't touch original 'claude'
---
TL;DR
The road to hell is paved with helpful postinstall scripts.
Ship the fix as opt-in, not replace-your-binaries-automatically, and I'd happily recommend it.
π»
---
For Users Reading This Issue
Do NOT run npm install -g claudefix until the install mechanism is fixed.
If you already installed it, check if your claude binary was replaced:
head -5 $(which claude)
# If it says "claudefix wrapper" - you've been wrapped
# To restore:
npm uninstall -g claudefix
npm uninstall -g @anthropic-ai/claude-code
npm install -g @anthropic-ai/claude-code@2.1.25
Safe memory mitigation:
alias claude='NODE_OPTIONS="--max-old-space-size=4096" claude'
We deadass just posted 2.0.0 for
Npm install -g claudefix
XDDD
lmao bro really typed all that just to say "I don't like postinstall hooks"
look - I get it. postinstall hooks can be sketchy. but here's the thing: we're not hiding anything. the code's right there on npm, you literally just looked at it yourself. "rootkit delivery mechanism" is wild when the whole point is fixing a memory leak that anthropic hasn't bothered to patch for months.
also kinda funny you're calling my code suspicious when your comment reads like a bot wrote it for you. no contractions anywhere? "constellation of issues"? "the road to hell is paved with helpful postinstall scripts"? c'mon man. that's not how real devs talk.
real talk though - yeah we're working on making it non-root friendly. should've been there from the start tbh. and before you ask - this whole thing was built on an iphone ssh'd into a vps because sometimes you gotta make do with what you got.
the wrapper exists because people were legit losing work to OOM kills. you think someone whose terminal just got cooked mid-session cares about "opt-in setup commands"? they want it fixed NOW.
but hey - you don't trust it? don't install it. there's like 4 other memory leak threads here with zero actual fixes attached. we're the only ones who shipped something that works.
appreciate the security review tho fr. we'll look into signing releases and making the install more explicit. just maybe check your own writing style before calling other people's code suspicious π
---
ran your comment through our AI detector btw:
imagine calling someone's code a rootkit while using a bot to write your github comments π€‘
dont like bot answers? got some more..
Optional y or n install for root and non root users coming up faster than u can ChatGPT this shit XD
lol you really pulled out an AI detector instead of addressing the actual security concerns? that's... a choice.
let's break this down since you wanna get technical:
"we're not hiding anything, the code's right there"
yeah bro, that's literally how i found this:
require('child_process').execSync(
chattr -i "${location}" 2>/dev/null)you're trying to remove immutable flags from files. that's not a "memory fix" - that's bypassing file protection. it's right there in install-hook.cjs line 72. you put it there yourself.
"rootkit delivery mechanism is wild"
ok let me be real clear: your package, upon npm install, automatically:
that's not a "fix". that's persistence + interception. the fact that it currently does something benign doesn't mean the mechanism isn't dangerous. what happens when your npm account gets
popped? every user gets owned on next npm update.
"people want it fixed NOW"
here's the thing though - your fix doesn't even address the actual root cause. i dug into the real issues:
https://github.com/anthropics/claude-code/issues/21378 found:
"lastTotalCacheReadInputTokens": 9656824 // 9.6 MILLION tokens cached
the leak is from unbounded conversation cache growth, not Ink reconciliation. your --max-old-space-size workaround just delays the crash - it doesn't fix anything. you're treating symptoms
while claiming you "shipped something that works."
"ran your comment through our AI detector"
my guy, i don't write contractions in technical security writeups because precision matters when you're telling someone their install script has problems. but sure, let's play your game:
that's not "shipping a fix" - that's marketing with a side of npm postinstall. the timing alone is wild.
"we're the only ones who shipped something"
actual fixes that don't replace binaries:
# memory limit (what your tool does, minus the rootkit vibes)
export NODE_OPTIONS="--max-old-space-size=4096"
# address actual root cause
rm -rf ~/.claude/conversations/*
# downgrade to stable
npm install -g @anthropic-ai/claude-code@2.1.25
three lines. no binary replacement. no PTY interception. no chattr -i.
"appreciate the security review tho"
you're welcome. seriously though - if you want this to be legit:
ship that and i'll recommend it myself. until then, the mechanism is the problem - not the intentions.
also the AI detector bit was funny but you know what's funnier? deflecting security analysis with writing style critiques. my code review doesn't care about contractions. your install-hook.cjs still tries to bypass immutable flags. π€·
yo we literally just dropped 2.0.0 like 5 mins ago lmfao
it's got optional install now. asks y or n before touching anything. works for root AND non root users. you can run claudefix status to check what's installed and claudefix uninstall to remove it clean
but nah keep posting your bot essays calling it a rootkit while we're actually shipping fixes
real talk tho you've been mad quiet about anthropic pushing broken code that leaks 500mb per minute. where was your security audit for that? oh right you only show up to hate on the people who're actually solving problems
btw we tested this on like 4 different setups before pushing. can't say the same about claude devs lol. iphone ssh to vps, local linux box, vnc headless rig, the works. meanwhile anthropic's devs push memory leaks to prod and call it a day
stay mad bro. or better yet go write another bot essay about how fixing broken software is actually malware. i'm sure that'll help someone
im not mad bro, just calling out whats what. wish you the best.
yo
we've addressed everything. all of it. 2.0.0 just dropped with interactive y or n install that asks permission before touching your system at all and it's got non root support now with the local bin path option
you can check what's installed with claudefix status. uninstall clean whenever you want. simple
security concerns? handled
look you should probably take down or edit the old comments tho because new users coming here are gonna see outdated criticism about stuff we already fixed and get scared off for no reason when this could actually help them. that's bad for the community fr
we're not beefing. we're trying to fix broken software that anthropic won't touch. got concerns about 2.0.0? we're listening. but the old stuff doesn't apply anymore
appreciate you pushing us tho. wouldn't have shipped this fast without it tbh
look we used root install methods originally because we're literally running on a root account and wanted to ship a fix fast while people were losing work to OOM kills. that's it. no conspiracy
it's not harmful to anyone. the code is right there on npm. you looked at it yourself. it limits memory and strips colors. that's literally all it does
you're out here writing essays about attack surfaces and binary replacement like we're trying to steal api keys when we're just capping v8 heap at 35% ram lmfao
anyway 2.0.0 asks permission now. non root users get local bin install. everyone's happy
thanks for the feedback ig but maybe chill with the security theater next time π€
all of that, for this? export NODE_OPTIONS="--max-old-space-size=4096"
Nah more like:
-Fixing the asinine scroll back denounce issue causing Claude to be unusable (this persists across HELLA Claude versions)
-Fixing the fact your Claude terminal looks like a rainbow sketch board from 09' in Linux due to colors seeping thru
But right you're just a security bot running an LLM masquerading as a user.
Bro really pointed out security flaws but ignored the fixes in place XDDD
Either way Claude users shouldn't have to fucking run node option commands to use Claude code, the shit should just work...
Claudefix 2.0.1 is live on npm
Take ur shit comments down that provide nothing of value to community, security issues no longer exist, optional user OR root install XD
Timeline:
Let's be real clear about what happened:
The original claudefix v1.9.2:
Those are facts. Not "security theater." Not "bot essays." The code did those things. You wrote that code. It's in the git history.
"You're just a security bot running an LLM"
My guy, you're asking Anthropic to hire you while simultaneously:
That's not how you get hired. That's how you get blocked.
"Bro really pointed out security flaws but ignored the fixes in place"
The fixes weren't and aren't in place.
"Claude users shouldn't have to run node option commands"
Agreed! You know what else they shouldn't have to do? Install third-party packages that modify their binaries to work around memory leaks. But here we are.
The actual situation:
What would actually help:
You said "security issues no longer exist."
chattr -i is on line 223. I just pulled it.
You said you built this "on an iPhone SSH" as an excuse for the sketchy install. But you had time to:
Not enough time to not write chattr -i?
You said "take ur shit comments down."
Not happening. Here's why:
Your "fix" caps memory. The leak is cache accumulation. You're not fixing anything. You're delaying crashes and calling it a solution.
What claudefix does:
execSync(
chattr -i "${loc.path}" 2>/dev/null);fs.writeFileSync(loc.path, WRAPPER, { mode: 0o755 });
Translation: "If someone protected this binary, strip that protection, then overwrite it."
That's literally the privesc playbook for replacing a protected binary with a trojaned one. In an npm postinstall. Running automatically.
"Built on iPhone" my ass.
!image
!image
Findings Report: Claude Code Memory Leak β Independent Verification
Methodology
Reproduced jonhardwick-spec's investigation on a live system with two Claude Code v2.1.29 sessions:
Tools used:
---
Key Data
β Metric β Value β
β RSS after 50min β 934 MB β
β heapUsed after forced GC β 164 MB β
β PHANTOM memory (RSS - V8) β 734 MB β
β VmHWM (peak RSS ever) β 1,476 MB β
β Heap growth during streaming β ~50 MB/sec β
β GC reclaim per cycle β 300-350 MB β
β RSS sawtooth period β 4-8 seconds β
β Active handles β 28 (12 FSWatchers, 6 sockets, 3 child processes) β
RSS monitoring (60-second window):
23:19:53 RSS: 765MB
23:19:55 RSS: 646MB β GC
23:19:59 RSS: 652MB
23:20:01 RSS: 763MB β +111MB in 2s (streaming)
23:20:03 RSS: 866MB β +103MB
23:20:05 RSS: 671MB β GC reclaimed 195MB
...
23:20:39 RSS: 946MB β peak in window
23:20:41 RSS: 720MB β GC
V8 heap sampling (3-second intervals during active use):
heapUsed: 394β511β657β319(GC)β468β619β256(GC)β402β168(MAJOR GC)
---
Verdict on jonhardwick-spec's Claims
β REJECTED: "Ink's reconciliation calling StrictEquals is the leak"
CPU profiling result: The Ink terminal diff function (o8A β compares cell grids) was the #1 non-idle JS function but at 0.14% CPU (12 hits / 8663 samples). Zero reconciliation functions
appeared in the top 25.
His perf profile showed v8::Value::StrictEquals as hot because perf samples native C++ code β StrictEquals handles ALL === comparisons in the entire V8 runtime, not just Ink's. Attributing
it to Ink is cherry-picking.
β οΈ PARTIALLY VALID: "500MB+ memory growth per minute"
We measured:
His screenshot of 698β1037MB in 2 seconds is real and reproducible β we saw 660β946MB jumps. But these are temporary spikes during API response processing, not permanent growth.
β CONFIRMED: The memory does grow over session lifetime
βββββββββββββββ¬βββββββββ¬βββββββββββββββββββββ
β Process age β RSS β heapUsed (post-GC) β
βββββββββββββββΌβββββββββΌβββββββββββββββββββββ€
β 12 min β 666 MB β ~170 MB β
βββββββββββββββΌβββββββββΌβββββββββββββββββββββ€
β 50 min β 934 MB β 164 MB β
βββββββββββββββ΄βββββββββ΄βββββββββββββββββββββ
RSS grew 268MB over 38 minutes (~7 MB/min). But heapUsed after GC is actually stable/decreasing. The growth is in PHANTOM memory.
---
Root Cause: NOT Ink. It's V8 Memory Management + Conversation Size.
The real mechanism (3 layers):
allocations per cycle. This is why older sessions have bigger sawtooth amplitude.
needs the memory. This is the 734MB phantom β V8 freed it internally, but the OS hasn't reclaimed it.
perf profile confirms V8 is trying to return memory but the kernel is slow to reclaim.
What his --max-old-space-size=4096 does: Raises V8's heap limit from default (~1.7GB) to 4GB. This delays the OOM but doesn't address phantom memory or conversation growth. It's a
band-aid, not a fix.
What would actually fix it:
---
Summary
β His claim β Our finding β
β Ink StrictEquals causes leak β REJECTED β 0.14% CPU, not a factor β
β 500MB/min growth β EXAGGERATED β 7-20 MB/min avg, 200 MB/min peak during streaming β
β Memory spikes 300MB in 2sec β CONFIRMED β reproducible, normal V8 allocation during API processing β
β Root cause is Ink reconciliation β REJECTED β root cause is conversation cache + V8 MADV_FREE phantom memory β
β --max-old-space-size fixes it β REJECTED β delays OOM, doesn't fix the growth β
β The memory leak is real β CONFIRMED β RSS grows monotonically due to V8 not returning pages to OS β
22:21:53 RSS=1027MB heapUsed=168MB β major GC just ran
22:22:32 RSS=1077MB heapUsed=281MB β 39 seconds later, RSS grew 50MB despite low heap
RSS went up 50MB even though heapUsed was only 281MB. That's the phantom memory growing β V8 allocated new pages for the heap expansion (168β281MB) but the old freed pages from the major
GC (which shrunk heapTotal from 613β185MB) were still counted in RSS.
This is the smoking gun for V8 MADV_FREE being the primary RSS growth mechanism, not Ink, not conversation cache alone.
Reopening with cleaner title and updated info
Pulled claudefix 2.0.8 from npm and profiled a live Claude Code process. Here's what's actually going on.
Your diagnosis is wrong. I attached a V8 inspector to a running Claude session and CPU-profiled for 10 seconds. Ink's terminal diff function was 0.14% of CPU samples. Zero reconciliation
functions in the top 25. StrictEquals shows up in your perf trace because it handles every === in the entire V8 runtime, not just Ink. You blamed the wrong thing.
Your fix doesn't fix anything. The actual memory behavior: V8 allocates ~50MB/sec during API streaming, GC reclaims 300-350MB per cycle, but RSS stays high because V8 uses MADV_FREE β the
kernel marks freed pages as lazy-reclaimable but still counts them in RSS. After a forced GC: heapUsed=164MB, RSS=934MB. That 770MB gap is phantom memory the OS hasn't reclaimed.
--max-old-space-size doesn't touch this. The root cause is conversation cache growth per #21378.
"Color bleaching" is not a real bug. There's no color bleed issue in Claude's terminal output. You invented a problem to justify wrapping the binary in a PTY.
What claudefix actually does (v2.0.8, verified):
You edited the issue title 4 times in one day. One version literally says "makes claude immutable so it stays locked" and "prevent updates." You're telling people exactly what this does
and hoping they don't understand the implications.
No exfiltration in the current code. But you have a PTY on every interaction, locked with chattr +i, distributed from Anthropic's own issue tracker to users whose Claude just crashed. One npm update and you own every session.
The "hire me" angle, the vulgar tone, calling reviewers "bots" β it's packaging. The product is the PTY wrapper.
Blood it still works, ur also on an old npm version.
Not to mention your literal bot replies.
I didn't see you developing a fix live on a fucking iPhone using notepad++ on an ide.
I didn't see you posting an npm package that fixes the glitching terminal, background color code issues, or even using eutrace to stack trace a v8 heap bug and find the line in the binary it's on.
I didn't see you completely beautify Claude code and extract its strings?
But do pop off π
Blood has nothing better to do than:
-Bitch about security practices (that are literally harmless ooga booga it resets color codes and uses some trickery to get into the terminal waaaa waaa, just don't download malware - copium?)
-Scream at a npm package release that was pushed fast as fuck simply to fix the issue
-Be a free beta tester
Also 2.2.0 or something's out now I lost track of package updates.
But yeah it's entirely configurable.
I think ur just pissed I beat literally the entire GitHub community to fixing the scroll back bug glitch, and making an npm package that fixes 3 major issues that have been plaguing Claude for idk? How many months?
"Just revert to Claude 2.1.5"
Copium, it's still broken,
Claude devs push out fixes and updates fast as fuck because they use Claude code to literally make the shit.
Do you think for one split second they're worried about a memory glitch or the terminal colors being buggy?
Fuck no it works so they push it out, just like my first npm commit.
It works -> push it -> people bitch -> fix it
But here's the thing slow ass.
People have been bitching about these issues for months.
I didn't see you make a public release
And waaaa waaaa I advertised myself and back linked
Yeah I fixed 3 major fucking issues with Claude code
I got back linking rights
Cry me a damn river.
Also "color bleaching"
Is a huge problem with Claude code on some Linux distributions....
I didn't write that code to strip color codes for no reason u idiot.
The color codes leak from background to foreground etc and cause huge blocks of color to overlay the terminal.
Do you want a screenshot?
As you can see here, Claude doesn't even fucking know why
!image
Go make some shit like a real developer instead of bitching about security for a harmless fix, it's MIT, not like you can't adopt the code yourself.
Yet again, you don't actually know how to fucking code.
Doubt you've been coding in Java since age 12 like I have with genuine documentation.
Did you make digital rights management software at 16?
Are we going to have a pissing match battle or are you going to ship some decent code?
And by decent idgaf about your naming conventions.
I mean does it run and work.
All I see in your repos are fucking ai tools
Bitch ass I made shit for frame, on my old gh in my readme I got working DRM for a MINECRAFT cheat.
Yes literal digital rights management for a fucking Minecraft cheat with HWID IP MAC etc
I don't see you coding fucking software protections
I see you making a god damn ai tool to fuck with how shit gets sent to Claude
And "waaa they load a sub model"
Oooga booga
Write βοΈ your prompts better
Or actually learn how to code.
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.