explainx.ai350K+ learn from us
TrendingAI News TodayPathwaysSkills
Pricing
explainx.ai

Upskill in AI — 16 free pathways, live workshops & bootcamps, and 50+ courses from practitioners. Plus the skills, tools, and MCP servers to practice on.

follow us

follow on google

Add explainx.ai as a preferred source

corporate training

support@explainx.ai

get started

Find your pathTake Free Evaluation

community

Join the community

learn

mind: share how you thinkpathways — start freeworkshopsbootcampscoursescompare Explainxcertificationsmock testsexplainx universitycorporate traininglearn skills & mcp

discover

skillsmcp serversexplainx mcpestacktoolsmdx readeragentsllmsdesignsdictionarypeopleagi trackerfelony benchranks

company

aboutvisionmissionteaminstructorsteach on explainxpartnershipscommunityhackathonscareers

content

daily AI newsstate of AI — live resultsblogreleasespromptsgeneratorsresource libraryfor LLMsexplainx.ai kids

solutions

all solutionsdeveloper upskillingmarketing upskillingproduct manager upskillingleadership upskilling

newsletter · weekly

Get AI news, tools, and insights in your inbox.

supportcontactprivacytermsdata rightshow we create contentsubmission guidelines

© 2026 AISOLO Technologies Pvt Ltd

explainx.ai

On this page

  • TL;DR
  • Why empty logs mislead
  • The presence request that nobody reads
  • Chromium, no-store, and why garbage collection is not enough
  • Timeline the author measured
  • Electron memory dumps are not “1.5 TB of RAM”
  • What developers can do now
  • What Chromium and Anthropic reportedly said
  • Minimal lesson for agent shipping teams
  • What developers are saying
  • What people are asking about the freeze
  • How fetch and keepalive interact here
  • Monkey patches the author shipped before the root cause
  • Related reading
← Back to blog

explainx / blog

Why Claude Desktop on Linux Freezes: A 27-Byte Telemetry Reply and an FD Leak

Claude Desktop, Anthropic, Claude Code, Developer Tools, Linux

Part of Anthropic and Claude

deafbeef traced Claude Desktop Linux freezes to unread no-store fetch bodies that leak Chromium file descriptors. What broke, how to detect it, and what to ask vendors to fix.

Nov 15, 2026·8 min read·Yash Thakker
add explainx.ai
go deep
Why Claude Desktop on Linux Freezes: A 27-Byte Telemetry Reply and an FD Leak

Claude Desktop on Linux can look healthy in logs, then freeze with placeholder skeletons or a stuck typing animation. Developer deafbeef spent two months patching a local install, captured a 1.5 TiB sparse renderer core dump (mostly reserved V8 sandbox address space, not RAM), and traced the hang to hundreds of two-megabyte shared-memory response pipes that each held the same 27-byte JSON payload: {"refresh_after_seconds":0}.

The write-up lives at blog.dfb.sh. It is not an official Anthropic post. It is one of the most detailed Chromium-in-Electron forensic stories tied to a frontier model desktop app in 2026, and it matters because coding agents increasingly ship inside desktop shells with always-on telemetry.

TL;DR

table · 2 cols
QuestionAnswer
SymptomUI skeletons, dead clicks, streaming replies frozen mid-token
Root mechanism (author)Unread Cache-Control: no-store bodies stay open in Mojo pipes → FD exhaustion
Triggering trafficClaude Code presence clear POST with keepalive: true, .catch(() => {})
Response payload27 bytes JSON refresh hint
Electron / ChromiumClaude Desktop Electron 44 ≈ Chrome 152 in the traced build
Datadog SDKBundled; not the sole holder of pipes per later repro
Fix statusPublic Nov 14–15, 2026 post; vendor ticket disputed
Daily briefFrom Yash · 350K+ students taught

Catch up on AI

One AI story explained in plain English, plus one thing to try. Every day, free. Unsubscribe anytime.

Why empty logs mislead

Main-process logs showed only “Main webview is unresponsive, will kill and reload” on a loop. Reload often failed. The renderer sometimes exited with FATAL: Crashing because hung, but stderr went to /dev/null until the author redirected it.

That pattern matches other Claude Desktop reliability threads where users blame the model when the shell is the bottleneck. Here the shell lost the ability to talk to its browser process because IPC backlog met descriptor starvation.

A rounded tank with green drops falling steadily from a small crack, echoing a slow descriptor leakA rounded tank with green drops falling steadily from a small crack, echoing a slow descriptor leak

The presence request that nobody reads

On the Code tab, Claude Desktop sends presence telemetry so the server knows a client is active. When the window is hidden or idle, it sends a clear:

text
POST /v1/code/channels/<id>/client/presence
{ "client_id": "...", "clear": true }

The author reports this variant uses:

javascript
fetch(url, { method: "POST", headers, body, keepalive: true }).catch(() => {})

So the client never awaits or reads the response body. The regular presence heartbeat does call await r.json(), per the post. Only the clear path is fire-and-forget.

The server’s reply is tiny but not empty: {"refresh_after_seconds":0} — 27 bytes.

Chromium, no-store, and why garbage collection is not enough

When Blink hands a response body to the renderer, it normally wraps it in BufferingBytesConsumer so chunks drain quickly. fetch manager skips that wrapper when the response carries Cache-Control: no-store (or when integrity checking is enabled).

For unread no-store bodies, data stays in the Mojo data pipe. Each pipe uses a 2 MiB shared-memory region and consumes one file descriptor in the renderer.

Two pipeline endpoints joined by a green adapter, echoing how a no-store fetch keeps a Chromium data pipe openTwo pipeline endpoints joined by a green adapter, echoing how a no-store fetch keeps a Chromium data pipe open

The author’s hung dump showed 942 such regions, 938 containing only the refresh JSON. Meanwhile TransferBuffer::Initialize() failed spammed the journal — classic FD limit pressure.

Initial suspicion fell on Datadog’s browser SDK, which records completed fetches in a Set capped at 1000 entries. Unread no-store responses never get resource timing events, so they linger. A later minimal repro without retaining Response objects still leaked 836 descriptors after 800 requests, proving Chromium does not close pipes on GC.

That nuance matters for security teams: you cannot fix this class of bug only by dropping telemetry vendor retention. The fetch caller must consume or cancel the body, or the browser must release the pipe on object destruction.

Timeline the author measured

table · 2 cols
PhaseObservation
Days 1–11Random renderer death; capped core dumps useless
Day 13Clean exit treated as intentional → blank UI until manual restart
Day 21+Verbose Chromium logging; GPU buffer failures mixed in
35-hour uptime sessionStreaming reply frozen at “6s · 246 tokens”; manual gcore while hung

A fresh renderer accumulated ~45 leaked SHM regions per hour from presence clears alone in the author’s test. Extrapolation explains multi-day uptimes crossing hundreds of pipes without a restart.

A protected key inside a capsule beside a closed folder, echoing kernel file descriptors the renderer never releasesA protected key inside a capsule beside a closed folder, echoing kernel file descriptors the renderer never releases

Electron memory dumps are not “1.5 TB of RAM”

Readers on Hacker News often misread sparse core files. Chrome 152 reserves about 1 TiB for the V8 pointer sandbox plus large guard regions so corrupted indices cannot escape. gcore reports virtual size, not resident pages. The author’s Rust parser used SEEK_HOLE / SEEK_DATA to search only mapped regions in under a second.

That technique is reusable for any Chromium hang where you cannot attach a debugger live.

What developers can do now

Mitigations (application side):

  1. Restart Claude Desktop on a schedule if you keep week-long sessions on Linux.
  2. Watch FD usage: sudden TransferBuffer errors in journald around Claude processes.
  3. Patch locally if you maintain a fork: read or response.body.cancel() on presence clear, even when JSON is useless.
  4. Raise ulimit -n only as a band-aid; pipes still cost kernel bookkeeping.

Mitigations (platform side):

  • Track Electron upgrades — the author notes newer Chrome builds may change pipe lifecycle (verify per release).
  • For internal Electron apps, audit keepalive + no-store combinations the same way you audit memory leaks.

Security posture: This is a denial-of-use bug, not remote code execution. It still matters in SOC workflows where analysts leave Claude Desktop open across shifts. Our desktop restriction guide covers containment patterns; this post adds reliability pressure on the same surface.

For coding-agent harness design, compare Claude Code CPU fixes and Cursor incident traces: desktop agents generate continuous side traffic; ignoring 27-byte replies is cheap until it is not.

What Chromium and Anthropic reportedly said

The author filed upstream. Chromium reportedly responded that behavior matches spec intent: unread no-store bodies should not be buffered in memory indefinitely, so the pipe stays open until consumed — consistent with the Fetch living standard guidance on suspending downloads.

The write-up also cites Chromium issue 342779913: upstream relanded a fix in Chrome 154 so Mojo fails more predictably under FD exhaustion instead of hanging silently. Claude Desktop’s traced build sits on Electron 44 / Chrome 152, so Linux users may not get that behavior until the shell upgrades.

An Anthropic ticket apparently auto-closed as not Claude Code, despite the stack trace originating in the Code tab presence client. Whether that categorization changes after the public post is unknown.

Builders should treat vendor triage labels as process noise when the reproduction crosses Electron + bundled observability SDKs + feature-specific fetch.

Minimal lesson for agent shipping teams

If your product sends heartbeat POSTs from an embedded webview:

  • Always drain or cancel bodies, even for “meaningless” JSON.
  • Do not assume .catch on fetch releases kernel resources.
  • Load-test FD counts, not just heap snapshots.
  • Separate telemetry SDK retention from browser networking contracts.

The same lesson applies to MCP-connected desktops and Bedrock-attributed IDE spend: the billing line item is visible; the descriptor leak is not, until the UI dies mid-task.

What developers are saying

The Hacker News thread was thin at crawl time (5 points, 1 comment), so there is little independent reproduction yet. When more Linux users confirm FD growth on lsof -p <renderer>, add numbers here — the author invited minimal repro without Claude binaries.

What people are asking about the freeze

Is this the same bug as high CPU in Claude Code CLI? No. explainx.ai covered Bun GC idle CPU as a separate runtime issue. The deafbeef trace is renderer networking state, not model inference cost.

Does restarting fix it permanently? Restart clears FD tables until presence clears accumulate again. For multi-day sessions, periodic restarts or a body-drain patch are the practical options the author describes.

Can I see it without a core dump? The post suggests watching open FD count on the renderer PID and journal lines like TransferBuffer::Initialize() failed. If those climb while idle, you are likely in the same failure class even before the UI freezes.

Should enterprises block Claude Desktop on Linux? That is a risk call. The failure is local availability, not remote exploitation. Security teams may still care because frozen agent sessions strand uncommitted work and encourage unsafe copy-paste recovery. Pair monitoring with the sandbox restrictions guide.

How fetch and keepalive interact here

The author highlights keepalive: true on the clear request. Keepalive lets the browser finish a request after navigation or teardown, which is useful for beacon-style telemetry. Combined with unread bodies, it extends pipe lifetime across task boundaries.

For application authors, the safe pattern is:

javascript
const response = await fetch(url, { method: "POST", headers, body, keepalive: true });
await response.body?.cancel();

Even when JSON is worthless, cancellation releases the pipe. Alternatively await response.arrayBuffer() on a 27-byte payload is cheap insurance.

Chromium’s no-store branch exists so sensitive bodies do not linger in memory. The trade-off is kernel resources until consumption. Agent products that poll every few minutes multiply that trade-off across workdays.

Monkey patches the author shipped before the root cause

Before the core dump, deafbeef layered local fixes on Claude Desktop: cap systemd-coredump size, reload the webview on clean-exit renderer deaths, and stream Chromium verbose logs into journald. Each patch reduced downtime but masked the underlying descriptor curve. That journey is familiar to anyone who maintained Electron chat clients during the early Slack desktop era: symptomatic reload loops until someone counts handles.

If you maintain an internal fork, consider feature-flagging presence clear during investigations, or route clears through a single shared worker that enforces body cancellation. Either approach beats asking users to tolerate minute-long UI freezes during long agent runs.

Related reading

  • Restrict Claude Desktop with sandbox patterns
  • Claude Cage: VM isolation for Claude Desktop
  • Claude Code Projects proactive coordinator
  • Exploit.cat on Claude Desktop Chromium patch gap
  • Cursor embedded-browser flaw round-up
  • What is MCP?

Electron version numbers, presence endpoint paths, and Datadog SDK behavior reflect deafbeef’s public post accessed 15 November 2026. Claude Desktop builds change frequently — confirm against your installed version.

Spotted something out of date? Let us know.
Daily briefFrom Yash · 350K+ students taught

Catch up on AI

One AI story explained in plain English, plus one thing to try. Every day, free. Unsubscribe anytime.

  • ✓ Free
  • ✓ One email a day, no spam
  • ✓ Unsubscribe anytime
Yash Thakker

Written by

Yash Thakker

Yash is an AI expert with over 300K learners. Join his workshops →

View Yash Thakker in People in AI →

Related posts

Nov 13, 2026

Claude Authentication Outage: claude.ai and Claude Code Down on November 13

On November 13, 2026 Anthropic opened a live incident on status.claude.com reporting authentication problems on claude.ai, the Claude Console, and Claude Code. The API stayed operational while the web and CLI surfaces showed major or partial outages through the morning UTC window.

Nov 13, 2026

Claude Code 2.1.323 Removes subagentStatusLine: What Broke and What to Do

Claude Code 2.1.323 removed the subagentStatusLine setting, and users who built agent dashboards on it say the panel went blank with no warning. Here is what the changelog says, what the GitHub issue and Hacker News commenters report, and what you can do today.

Oct 29, 2026

Claude Code agent_summary: Does a 3-Word Status Line Really Burn 16% of Your Tokens?

A Flamerix AI gist claims Claude Code spends up to a fifth of its requests on a 3-5 word status line for background agents. A GitHub issue from August and Hacker News testers give a more nuanced picture: real, but it depends on how many subagents you run.