Where does the bug appear (feature/product)?
Cursor IDE
Describe the Bug
Environment
- Cursor 3.20.21 (commit f09fca384ceca23f7bf21f9c23655b162641d740, VS Code 1.128.0)
- Electron 42.10.0 / Chrome 148.0.7778.280
- macOS 26.5.2 (25F84), Apple M4 (Mac16,10)
- anysphere.remote-ssh 1.1.16
- 6 windows: 4 Remote-SSH (two hosts), 2 local. Cursor had been running for ~2.5 days.
Summary
With no user activity, three Cursor processes each used one full core for many hours:
- the main process (
Cursor) - the renderer of a Remote-SSH window
- the renderer of a local window (no remote involved)
In every case the hot thread is the Chromium IO thread (Chrome_IOThread in main, Chrome_ChildIOThread in renderers). It is not processing messages; it is spinning on kevent64 / mach_msg without blocking. The other renderers stay at ~0.7%.
Separately, a Remote-SSH window stayed in “reconnecting” for 21 hours after the network came back, because the reconnect path awaits resolveAuthority with no timeout.
On a laptop on battery this drains the battery while the machine looks idle.
Issue 1: IO thread busy loop
Measurements (2-second deltas, top -c d -stats pid,cpu,csw,msgsent,msgrecv,sysbsd,sysmach)
| Process | %CPU | BSD syscalls / 2 s | Mach syscalls / 2 s | Mach msgs sent | Mach msgs received |
|---|---|---|---|---|---|
| Renderer, local window | 102.0 | 3,190,150 | 3,189,588 | 1,099 | 637 |
| Renderer, SSH window | 100.8 | counter saturated at 2,147,483,647 | saturated | 834 | 421 |
| Main process | 100.5 | 2,910,973 | 2,911,021 | 58 | 11 |
| Renderer, SSH window (healthy) | 0.8 | 2,047 | 1,699 | 844 | 423 |
| Renderer, local window (healthy) | 0.7 | 2,007 | 1,619 | 810 | 404 |
The spinning processes exchange the same number of Mach messages as healthy ones, yet make ~1,500x more syscalls, in a 1:1 BSD:Mach ratio. That is kevent64 returning immediately followed by a mach_msg that receives nothing, about 1.5 million times per second.
Per-thread CPU (ps -M)
Exactly one thread per process is at ~99%, with system time exceeding user time:
- main:
Chrome_IOThread, STIME 613 min, UTIME 552 min - SSH renderer:
Chrome_ChildIOThread, STIME 713 min, UTIME 409 min - local renderer:
Chrome_ChildIOThread, STIME 573 min, UTIME 331 min
sample self-time of the hot thread
Chrome_ChildIOThread (SSH renderer, 857 samples)
64.1% mach_msg2_trap
21.8% kevent64
3.7% v8::MicrotasksScope::MicrotasksScope (symbolication approximate)
1.3% mach_absolute_time
...
An idle thread in the same process (Compositor) shows 100% in a single kevent64 frame, as expected. The spread across mach_msg2_trap, kevent64, mach_absolute_time and user code shows the IO thread is running, not blocked. The JS main threads are idle.
When it started
It is not reproducible on demand. Estimated from accumulated CPU time, spinning began on 2026-09-30 between roughly 15:00 and 20:00 JST, in all three processes. At 14:12 JST that day every Remote-SSH connection dropped at once (network outage), so the outage is a candidate trigger, but this is not confirmed. Once started, the spin never stops on its own; only restarting the process clears it.
Expected
The message pump should block in kevent64 when there is nothing to receive. If an event source stays signaled but yields no message, it should be removed or backed off, and ideally reported, rather than spun on indefinitely.
Issue 2: reconnect waits forever in resolveAuthority
Log (window15/renderer.log, Remote-SSH to www.riis.okayama-u.ac.jp)
2026-09-30 14:13:05.495 [info] Invoking resolveAuthority(ssh-remote)...
2026-09-30 14:13:05.495 [info] [LocalProcess0][resolveAuthority(ssh-remote,2)][0ms] obtaining proxy...
...
2026-10-01 11:04:00.907 [info] [remote-connection][Management ][8457f…][reconnect] received socket timeout event (unacknowledgedMsgCount: 47924, timeSinceOldestUnacknowledgedMsg: 75075362, timeSinceLastReceivedSomeData: 75713154).
2026-10-01 11:04:10.876 [info] [LocalProcess0][resolveAuthority(ssh-remote,2)][75065355ms] waiting...
2026-10-01 11:06:49.637 [error] resolveAuthority(ssh-remote) returned an error after 75220739 ms Canceled
resolveAuthoritywas pending for 75,220,739 ms (20.9 h). It ended only when the window was closed.- The network had recovered long before; other windows to the same host were connected.
- Unacknowledged protocol messages grew to 48,018 and were never dropped.
- The “waiting…” line is logged every second per extension host, making up most of this 34,700-line log.
Another window (window11, kanri.chem.okayama-u.ac.jp) shows the same hang for 8,661,684 ms (2.4 h). When the pending call was canceled, it reconnected in 4.5 s:
2026-09-30 18:57:33.168 [error] resolveAuthority(ssh-remote) returned an error after 8661684 ms Canceled
2026-09-30 18:57:42.140 [info] resolveAuthority(ssh-remote) returned 'WebSocket(127.0.0.1:54764)' after 4478 ms
The request never reached Remote-SSH: the local extension hosts froze
The Remote-SSH output for that window pinged the server every minute and then stopped at 14:01:51. It logged nothing for the next 21 hours, including no “Received re-connection request”. The renderer reported both local extension hosts of that window as unresponsive and never as responsive again:
2026-09-30 14:12:45.437 [info] Extension host (LocalProcess [role: always-local] pid: 59299) is unresponsive.
2026-09-30 14:13:08.523 [info] Extension host (LocalProcess [role: user] pid: 59298) is unresponsive.
The same thing happened at the same moment in another Remote-SSH window (pids 60265 and 60257). The frozen hosts sit at 0% CPU, so they are blocked, not busy. Pids 59298 and 59299 were still alive 22 hours later, after their window had been closed (leaked processes).
So resolveAuthority was sent to an extension host that would never answer, and the workbench had no timeout to notice.
Cause in code (workbench.desktop.main.js, minified)
In _runReconnectingLoop, the authority is resolved before any timeout is armed:
const c = await vCh(this._options, this.reconnectionToken, this.protocol, t); // -> addressProvider.getAddress() -> resolveAuthority, no timeout
// ...
const u = setTimeout(() => l.cancel(), this._options.reconnectTimeoutMs ?? gsb); // 30 s, armed only after resolve returns
and the resolve itself:
c.cancelAndSet(() => s("waiting..."), 1e3); // only logs
const l = await a.resolveAuthority(e, t, n); // no timeout
Because this await never settles, none of the safeguards run: the 30 s reconnect timeout, the backoff schedule [0,5,5,10,...,120] s, and the 3 h grace period that turns into a permanent failure. remote.SSH.connectTimeout (30 s) does not help either, since the hang is above the extension’s connect logic.
Expected
- Put a timeout (e.g.
remote.SSH.connectTimeoutor the 30 s reconnect timeout) onresolveAuthorityduring reconnection, cancel it on expiry, and fall through to the existing backoff and grace-period logic. - When a local extension host stays unresponsive (here, for 21 hours), restart it or tell the user, instead of waiting on it silently.
- Terminate a window’s extension hosts when the window is closed.
Related reports (none with this signature)
- [Memory/CPU leak in “Cursor Agents” window renderer after long-running sessions] : staff wrote on 2026-09-15 that “the sustained high CPU with no agent activity is still under investigation”. That thread is about the Agents window and JS-side leaks; here the windows are regular editor windows and the time is spent in the native IO thread, including in the main process.
- [Cursor 3.19.13 maintains ~50% CPU at idle]: renderer plus GPU process, with the main process near 0%. Different profile.
- [electron/electron#24385]: idle 100% CPU on macOS from a libuv clock bug, fixed in 2020. Same symptom, different code path.
- microsoft/vscode-remote-release#8046, [#11648]: reconnect failures and requests for a reset without reloading, but not a
resolveAuthoritythat never settles because the extension host froze.
(Links are removed by request)
Workaround
Quit Cursor completely (Cmd+Q) and relaunch. Reloading a window is not guaranteed to replace the renderer process.
Steps to Reproduce
During after-work duration. When I came back to the office, it fills 400% of CPU without doing anything.
Operating System
MacOS
Version Information
Cursor 3.20.21 (commit f09fca384ceca23f7bf21f9c23655b162641d740, VS Code 1.128.0)
Does this stop you from using Cursor
No - Cursor works, but with this issue