Where does the bug appear (feature/product)?
Cursor IDE
Describe the Bug
Cursor’s auto-update hard-crashed my Mac 3 times in one evening — here’s the forensic evidence
Cursor version: 2.6.20
Machine: MacBook Pro M3 Max, 36 GB RAM, macOS 26.3
Date: 2026-05-17
What happened
My Mac hard-crashed and rebooted itself three times in a single evening — at 19:15, 20:35, and 22:06. Not kernel panics. Worse: Apple Silicon watchdog timeouts — the system became so unresponsive that the hardware watchdog forced a reset.
Every single crash was caused by Cursor’s auto-update.
The evidence
Crash #1 — 19:15
macOS DiagnosticReports captured /usr/bin/ditto extracting a zip file. ditto was spawned by Cursor (Resource Coalition 1439 = com.todesktop.230313mzl4w4u92). The stack trace shows BOMCopierCopyWithOptions → _BOMCopierCopyFromPKZip with 35+ levels of recursive _copyDir calls. It ran for 11 minutes and wrote 2.15 GB before the watchdog fired.
Crash #2 — 20:35
After the reboot, Cursor auto-started and resumed the update. The diagnostic report this time shows 177 threads all blocked in write() via libuv’s uv__fs_post — your Electron thread pool completely saturated. Simultaneously, the Squirrel.framework thread was in isVersionStandard → removeItem → __removefile_tree_walker, recursively deleting the old version. 14.3 MB/s sustained writes over 150 seconds. Watchdog fired again.
Crash #3 — 22:06
After this reboot, Cursor started again. The main log at logs/20260517T204749/main.log tells the story:
20:47:49 updateURL .../cursor/2.6.20/...
22:04:36 update#setState checking for updates
22:04:37 UpdateService onUpdateAvailable()
22:04:37 update#setState downloading
Within 2 minutes of starting the download, the watchdog fired. ResetCounter confirms: Boot faults: wdog, reset_in_1 timeout.
The smoking gun
The ShipIt state file (ShipItState.plist) still points to an incomplete update:
updateBundleURL → "update.z1tErYz/Cursor.app/"
targetBundleURL → "/Applications/Cursor.app/"
And ShipIt_stderr.log shows the install was attempted twice the day before and never succeeded:
2026-05-16 19:24:28 Detected this as an install request
2026-05-16 23:01:03 Detected this as an install request
The update never completed. So after every watchdog reset, Cursor restarted, detected the incomplete update, and tried again. Crash. Reboot. Repeat.
Why this is unacceptable
-
An IDE should never be able to take down the entire OS. No amount of disk I/O from a user-space application should cause a watchdog timeout on a 36 GB M3 Max machine. This is egregious behavior.
-
The Squirrel update mechanism has no backoff or circuit breaker. It failed, crashed the machine, and then immediately tried the exact same thing again after reboot. Twice. There’s no “maybe we shouldn’t do that” logic anywhere in the pipeline.
-
177 concurrent file writes + recursive directory deletion + zip extraction all happening simultaneously means nobody thought about I/O contention. The update process apparently fires off work on every available thread without any concurrency control.
-
This is a crash loop generator. By combining auto-start on boot with a failing update, you’ve created a mechanism that can render a machine unusable until someone knows how to SSH in or boot into safe mode to clean up the ShipIt state.
What you need to fix
- Put a concurrency limit on libuv thread pool usage during updates. 177 simultaneous
write()calls is absurd. - Add exponential backoff to update retries. If the last update attempt didn’t complete successfully, do not immediately retry on next launch.
- Add a staged update mechanism. Download, extract, and install should not all happen on app launch while the main process is also doing heavy I/O.
- If a watchdog or unexpected shutdown is detected on next boot, abort the pending update instead of retrying it.
How I stopped the bleeding
rm -rf ~/Library/Caches/com.todesktop.230313mzl4w4u92.ShipIt/update.*
rm -f ~/Library/Caches/com.todesktop.230313mzl4w4u92.ShipIt/ShipItState.plist
defaults write com.todesktop.230313mzl4w4u92 SUEnableAutomaticChecks -bool false
Disabled your auto-update entirely. I won’t be enabling it again until this is acknowledged and fixed.
All diagnostic reports, system logs, and stack traces are available. Happy to provide them to any Cursor engineer who wants to investigate.
Steps to Reproduce
Steps to Reproduce
- Install Cursor 2.6.20 on a Mac with auto-update enabled (default).
- Wait for Cursor’s Squirrel updater to detect a new version and download the update zip. The update is downloaded to
~/Library/Caches/com.todesktop.230313mzl4w4u92.ShipIt/update.<random>/. - Squirrel spawns
/usr/bin/dittoto extract the zip into the target location. This extraction is deeply recursive (the update package contains many nested directories). - Simultaneously, Squirrel begins recursively deleting the old version via
__removefile_tree_walker, while Cursor’s main process continues normal operation (extensions, language servers, file watchers — all generating their own disk I/O). - The combined I/O load — ditto recursive extraction + Squirrel recursive deletion + 177 libuv threads in write() + normal workspace I/O — saturates the APFS I/O stack. The kernel becomes unresponsive.
- Apple Silicon hardware watchdog fires → forced system reset.
- After reboot, Cursor auto-starts (macOS window restoration). Squirrel detects the incomplete update from
ShipItState.plist. Goes back to step 2. - Repeat until someone manually cleans up the ShipIt state.
Operating System
MacOS
Version Information
Version: 2.6.20
Commit: b29eb4ee5f9f6d1cb2afbc09070198d3ea6ad760
Date: 2026-03-17T01:50:02.404Z
Browser: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Cursor/2.6.20 Chrome/142.0.7444.265 Electron/39.8.1 Safari/537.36
Does this stop you from using Cursor
Yes - Cursor is unusable