An open Canvas leaks PNG snapshots into blob_storage (46 GB in ~3 h); once the blob quota is full, Remote-SSH gets stuck in an endless reconnect loop

Title: An open Canvas leaks PNG snapshots into blob_storage (46 GB in ~3 h); once the blob quota is full, Remote-SSH gets stuck in an endless reconnect loop

Summary

I left an agent-generated Canvas open in an editor tab. For as long as it stayed open, Cursor stored a new 1440×1000 PNG snapshot of it about once a second and never released any of them. ~/Library/Application Support/Cursor/blob_storage reached 46 GiB in about 2.5 hours. That matches Chromium’s blob disk quota (10% of my 460 GiB disk). After that my Remote-SSH window stopped working: it reconnected every 20 seconds, the Explorer stayed empty, editors were blank, and it logged “The remote extension host took longer than 60s to send its ready message”. Reloading the window didn’t help. Only quitting Cursor completely (Cmd+Q) fixed it.

Environment

  • Cursor 3.15.6 (darwin-arm64) when this happened. The remote server was commit a1f686545fd0ce8917bbd2449f733551a9bce420.
  • Cursor auto-updated to 3.22.7 (commit 37076c6c3f9e253c0fa2305197e45befd13a2260, VS Code 1.128.0) when I restarted.
  • macOS 26.5.2 (25F84), Apple M5, 24 GB RAM, 460 GiB disk
  • anysphere.remote-ssh 1.1.16, connected to a Linux x64 host

1. Canvas snapshot leak (main issue)

Steps

  1. Have the agent create a Canvas. Mine was a static ~160 KB .canvas.tsx report page with tabs. It contains no timers or animations, and no toBlob, toDataURL or createObjectURL calls.
  2. Leave the canvas tab open. I left it open for a few hours after the conversation ended.
  3. Watch du -sh ~/Library/Application\ Support/Cursor/blob_storage.

Expected: blob_storage stays small.

Actual:

  • blob_storage/<session>/ filled up with 9,610 page files (46 GiB). Nearly all were written between about 20:50 and just before midnight; the peak was 25.5 GB in a single hour.
  • 9,603 of those files held a PNG snapshot of the canvas (IHDR 1440×1000, 8-bit RGB, about 5.2 MB each).
    • 9,369 files were exactly one PNG each.
    • The other 234 had a small remote-protocol message blob in front of the PNG.
  • Files written at 21:37, 22:05 and 22:42 are byte-identical (same MD5). The unchanged canvas was being captured over and over.
  • The growth started when the canvas was created (20:51). It continued for about 2 hours after the agent conversation had finished (21:32), and stopped only when the quota was full.
  • Closing the canvas tab released nothing (still 46 GiB and 9,610 files). Only a full quit freed it, because Chromium deletes the old blob directory at startup.
  • I haven’t re-tested this on 3.22.7 yet.

2. Why this took down Remote-SSH (the code path looks fixed in 3.22.7)

In 3.15.6, BrowserWebSocket received each message as a Blob and read it with a single FileReader that had only an onload handler (de-minified from workbench.desktop.main.js):

this._fileReader.onload = e => { this._isReading = false; this._onData.fire(e.target.result); /* then read the next queued blob */ };
const enqueue = blob => { if (this._isReading) { this._queue.push(blob); return; } this._isReading = true; this._fileReader.readAsArrayBuffer(blob); };

Once the blob quota was exhausted (BlobStatus::ERR_OUT_OF_MEMORY), readAsArrayBuffer failed. _isReading then stayed true forever, so every later message was queued and never delivered. What followed:

  • The client timed out every 20 seconds: received socket timeout event (unacknowledgedMsgCount: 351, timeSinceOldestUnacknowledgedMsg: 20439, timeSinceLastReceivedSomeData: 20401).
  • The server logged The client has reconnected. every 20 seconds.
  • On every reconnect the server replayed the same ~7 MB unacknowledged backlog. netstat showed 7,007,480–7,007,536 bytes delivered to the renderer’s WebSocket each time, and then the connection stalled again.
  • The remote server was idle, its socket queues were empty, and SSH round trips were ~50 ms.
  • Reloading the window doesn’t help because the blob quota is shared by the whole app.

In 3.22.7, BrowserWebSocket sets binaryType = "arraybuffer" and no longer uses a FileReader, so this particular path seems fixed. I’m including it because it’s what turned a disk leak into a full outage. Any other code that reads Blobs through a FileReader without onerror would fail the same way.

3. Minor: orphaned ssh processes

Each window reload during the loop left the previous ssh -T -D <port> ... bash --login -c bash process running with PPID 1. Eight of them piled up in about an hour (remote-ssh 1.1.16).

Suggested fixes

  • Canvas: don’t re-capture a canvas that hasn’t changed; release or revoke snapshot blobs and object URLs; cap how many snapshots are kept.
  • Wherever Blobs are read through a FileReader: handle onerror and onabort.
  • Remote-SSH: kill the ssh child process when its extension host exits.

Does this stop you from using Cursor?

Yes. The Remote-SSH window was unusable until I fully quit Cursor. I can share renderer.log, Remote - SSH.log and main.log on request.

Hi there!

We detected that this may be a bug report, so we’ve moved your post to the Bug Reports category.

To help us investigate and fix this faster, could you edit your original post to include the details from the template below?

Bug Report Template - Click to expand

Where does the bug appear (feature/product)?

  • Editor, Tab & Chat (autocomplete, Composer, in-editor agent)
  • Terminal & commands
  • Models, pricing & API keys (availability, Auto/Max, BYOK/Bedrock)
  • MCP & tools
  • Cloud Agents & Automations (cursor.com/agents, scheduled/event)
  • BugBot & Code Review
  • Cursor CLI
  • Cursor Mobile
  • Remote (SSH / Dev Containers / WSL)
  • Account, billing & login
  • Something else…

Describe the Bug
A clear and concise description of what the bug is.


Steps to Reproduce
How can you reproduce this bug? We have a much better chance at fixing issues if we can reproduce them!

  1. …
  2. …
  3. …

Expected Behavior
What is meant to happen here that isn’t working correctly?


Screenshots / Screen Recordings
If applicable, attach images or videos (.jpg, .png, .gif, .mp4, .mov)


Operating System

  • Windows 10/11
  • MacOS
  • Linux

Version Information

  • For Cursor IDE: Menu → About Cursor → Copy
  • For Cursor CLI: Run agent about in your terminal
IDE:
Version: 2.xx.x
VSCode Version: 1.105.1
Commit: ......

CLI:
CLI Version 2026.01.17-d239e66

For AI issues: which model did you use?
Model name (e.g., Sonnet 4, Tab…)


For AI issues: add Request ID with privacy disabled
Request ID: f9a7046a-279b-47e5-ab48-6e8dc12daba1
For Background Agent issues, also post the ID: bc-…


Additional Information
Add any other context about the problem here.


Does this stop you from using Cursor?

  • Yes - Cursor is unusable
  • Sometimes - I can sometimes use Cursor
  • No - Cursor works, but with this issue

The more details you provide, the easier it is for us to reproduce and fix the issue. Thanks!

Hey @Aillen_Yang, thanks for the detailed write-up and the de-minified socket code, it really helps.

You’re right about the reconnect loop. In newer versions, remote traffic is no longer read via Blob plus FileReader, so that part shouldn’t repeat on 3.22.7. That same change likely fixes the disk growth too, so I’d like you to double-check the canvas behavior on 3.22.7:

  1. Check the version in Cursor > About Cursor, it should be 3.22.7.
  2. With Cursor running, open Terminal and run:
    du -sh ~/Library/Application\ Support/Cursor/blob_storage; find ~/Library/Application\ Support/Cursor/blob_storage -type f | wc -l
    
  3. Connect to the same Linux host via Remote-SSH.
  4. Open the same canvas in the editor and keep it visible for 10 minutes without touching anything.
  5. Run the command from step 2 again.

Does the size or the file count keep growing? If yes, please try the same canvas in a local non-SSH window and tell me if it grows there too. Also let me know if the agent used browser or screenshot tools on that canvas during the run.

If the growth still happens, please attach renderer.log, main.log, and Remote - SSH.log from that session.

I also forwarded your note about leftover ssh processes after reloading the window to the team.