Remote-WSL: permanent 20 s reconnect loop under WSL2 mirrored networking — client hard-codes 127.0.0.1 (via wslrelay.exe), which deadlocks on the connect-time burst

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

In a Remote-WSL window under WSL2 networkingMode=mirrored, the Management connection drops and
reconnects every ~20.5 s, indefinitely, starting 20 s after the first connect. Agent chat hangs on
“Taking longer than expected” / “Planning next moves” and then fails with:

The agent execution provider did not respond in time. This may indicate the extension host is not
running or is unresponsive.

Renderer log, every cycle:

[remote-connection][Management][…][reconnect] received socket timeout event (unacknowledgedMsgCount: 1886, timeSinceOldestUnacknowledgedMsg: 20502, timeSinceLastReceivedSomeData: 20425)
[remote-connection][Management][…][reconnect] starting reconnecting loop.
[remote-connection][Management][…][reconnect] reconnected!

unacknowledgedMsgCount grows by a constant ~1876 per cycle and never resets (1886, 3762, 5638 …
230,808 after two hours). The ExtensionHost connection to the same server/port never drops. Server-side
remoteagent.log shows “[ManagementConnection] The client has reconnected.” every 20.5 s, and the remote
extension host never gets far enough to write exthost1/ logs. One Windows socket leaks per cycle
(ESTABLISHED forever; 640+ observed).

ROOT CAUSE (instrumented, reproduced without Cursor):

  1. anysphere.remote-wsl resolves the authority as new ResolvedAuthority("127.0.0.1", port, token).
    Under mirrored networking, Windows→WSL 127.0.0.1 traffic is carried by Microsoft’s user-mode relay
    wslrelay.exe --mode 1.
  2. At connect, the server sends ~1.69 MB on the Management channel — two single protocol messages of
    849,769 B (scanExtensions result) and 835,553 B (getInstalled result), chunked into 256 KB WebSocket
    frames — WHILE the client is sending ~700 KB of remoteFilesystem.readFileStream / watch / stat RPCs to
    restore its editors (≈1,900 messages in the first second).
  3. wslrelay.exe deadlocks when both directions carry bulk data concurrently (measured thresholds: roughly
    ≥300–600 KB one way and ≥200–300 KB the other). Chromium NetLog (–log-net-log) shows the network
    service receiving two 256 KB frames and then nothing; it logs 661,911 B sent while the server receives
    only 33,745 B per cycle; ss on the server socket shows rwnd_limited: 100%.
  4. After the 20 s keepalive timeout, PersistentProtocol reconnects and BOTH sides replay their entire
    unacknowledged backlog at once (endAcceptReconnection) — exactly the pattern that deadlocks the relay —
    so the loop never exits, and every replay leaks another socket.

This reproduces with a 30-line Python server + PowerShell client and no Cursor involved; the same
transfer via the host’s mirrored IP completes normally.

Steps to Reproduce

  1. WSL2 with networkingMode=mirrored in .wslconfig.
  2. Open a Remote-WSL window on a workspace with a few hundred restored editors (in my case ~218 open
    files across several folders) — enough that the workbench issues ~700 KB of file-read RPCs at connect.
  3. Start an agent chat, or just watch Help > Toggle Developer Tools / the renderer log.

No other extensions are required: the loop reproduces with --disable-extension on every user and built-in
extension, and from the first 20 seconds of every fresh session.

Expected Behavior

The Remote-WSL connection stays up; agent requests complete.

Operating System

Other

Version Information

Cursor 3.21.18 (commit c4730f7d93d787d9ab120af715999f0345ee5bc0, VS Code 1.128.0, built 2026-09-22)
Also reproduced on 3.17.19 (commit ae3a2b7231dd56194447fe4570dfdc61640b1e90) before updating.
Remote-WSL extension: anysphere.remote-wsl 1.0.13 (unchanged across both client versions)
Windows 11 build 10.0.26200.8875 (x64); WSL 2.7.14.0, kernel 6.18.33.2-microsoft-standard-WSL2, Ubuntu 24.04
.wslconfig: networkingMode=mirrored, dnsTunneling=true

For AI issues: which model did you use?

N/A — connection-layer issue; any model fails the same way.

For AI issues: add Request ID with privacy disabled

81f49275-e578-429c-9376-a1f745abe7c8
87fbc4ea-72c4-4ff8-ba35-e686d087b22c

Additional Information

CONSOLE ERRORS (renderer.log / Developer Tools, during the loop)

[error] Error: No Connect transport provider registered.
at async forceRefreshServerConfig (…/out/vs/workbench/workbench.glass.main.js)
at async createSingleServer …
[warning] [agent-exec] Provider registration timed out (attempt 6/9, timeout=5000ms), retrying
[warning] [agent-exec] Provider registration timed out (attempt 7/9, timeout=5000ms), retrying
[warning] [agent-exec] Provider registration timed out (attempt 8/9, timeout=5000ms), retrying
[warning] [WorktreeManager] Timed out waiting for git context provider, skipping worktree discovery
[error] {“isTrusted”:true}
[info] [remote-connection][Management][…][reconnect] received socket close event (wasClean: false, code: 1006, reason: )

WORKAROUND (verified: 0 reconnects where it was previously 100% reproducible)

  1. Setting “remote.WSL.serverListenAddress”: “0.0.0.0” — this setting already exists and its own
    description says it is for networkingMode=mirrored.
  2. Edit anysphere.remote-wsl-1.0.13/dist/main.js: replace
    ResolvedAuthority(“127.0.0.1”
    with
    ResolvedAuthority(“HOST_IP”
    where HOST_IP is the host’s own (mirrored) IPv4 address. resolveAuthority(wsl) then returns
    WebSocket(HOST_IP:PORT), the server sees the peer as the vEthernet address, and the loop is gone.
    Obviously fragile (hard-coded IP, undone by extension updates) — hence this report.

REQUEST

  • Add a remote.WSL.connectAddress setting (or remote.WSL.connectThroughLocalhost: false), or
    automatically use the host’s mirrored IP when networkingMode=mirrored is detected. The
    serverListenAddress=0.0.0.0 half already exists; the connect half is missing.
  • Consider chunking or deferring the two ~850 KB extension-scan messages sent at connect. Even after
    Microsoft fixes the relay, sending 1.7 MB in two messages while the workbench restores editors — and
    replaying all of it on every reconnect — amplifies any transport hiccup into a hard loop.

Does this stop you from using Cursor

Yes - Cursor is unusable

Correction

After feedback from the WSL team on microsoft/WSL#41680, I determined that my WSL instance is actually runningnfo --networking-mode = nat`).

My .wslconfig requests networkingMode=mirrored, but WSL is silently falling back to NAT. As a result, the relay involved here is NAT-mode localhost forwarding (wslrelay.exe --mode 1), not mirrored networking.

Microsoft has confirmed this is a known NAT-mode issue and is working on a fix: microsoft/WSL#41458.

Findings That Still Apply

Everything else in this report remains valid:

  • The deadlock itself.
  • The connect-time traffic burst that triggers it:
    • ~1.7 MB of extension-scan messages from the server.
    • ~0.7 MB of editor-restore RPC traffic from the client.
  • The reconnect replay behavior that turns the issue into a permanent failure loop.
  • The workaround of connecting directly to the WSL VM’s IP instead of 127.0.0.1.

Notes for the Cursor Team

1. Make WSL-IP Connections Resilient

In NAT mode, the VM IP changes whenever WSL is restarted. This means the current workaround (connecting directly to the VM IP) breaks after every wsl --shutdown or system reboot.

A remote.WSL.connectAddress setting that resolves the VM’s current IP at connection time would make this workaround practical. For example, the extension could obtain the address from hostname -I within the distro, similar to how it already discovers the server port.

VS Code’s Remote-WSL extension exposes a comparable capability through remote.WSL.server.connectThroughLocalhost.

2. Consider Client-Side Mitigations

Even with the upstream WSL fix in progress, there are client-side mitigations worth considering:

  • Chunk or defer the two ~850 KB extension-scan messages rather than sending them immediately during connection establishment.
  • Avoid replaying the entire pending backlog from both sides simultaneously after reconnect.

The reconnect replay appears to be what transforms a transient transport stall into a persistent failure loop.

Hey @epic_bell, Thanks for the repro and the NAT correction.

Your read matches ours, and it’s not something you misconfigured. This is an issue we’re tracking, and I’ve passed along both of your asks (a connect-address option, and shrinking/chunking the connect-time burst). No timeline yet, but I’ll post here when there’s an update.

To unblock in the meantime:

  1. Your patched extension (dialing the distro’s IP instead of 127.0.0.1) is the most reliable fix. Caveats you already flagged: it’s overwritten on extension updates, and in NAT mode the VM IP changes after wsl --shutdown or a reboot.
  2. If you’d rather not patch, shrink the connect-time burst: close most restored editors first (Command Palette, “View: Close All Editors”), then “Developer: Reload Window”. Trimming installed remote extensions helps too.

Thanks again for filing upstream with the WSL team.

Same failure here, on NAT mode with GlobalProtect connected.

  • Stable for weeks. Cursor updated to 3.24.12 at 10:11 AM on 13 Oct 2026. The 10:12 and 10:19 sessions stayed connected. The noon session reconnected 266 times. A second update, to 3.24.18, landed at 5:55 PM, after the loop was already running. WSL was still 2.7.3 on kernel 6.6.114 the whole time.
  • The Management connection timed out every 20 seconds: `timeSinceLastReceivedSomeData` about 20000, `unacknowledgedMsgCount` climbing past 370. The extension host on the same port stayed up. `remoteagent.log` logged `[ManagementConnection] The client has reconnected.` each cycle.
  • `wslrelay.exe` was the Windows listener. Inside Ubuntu, about 58 sockets sat in `CLOSE-WAIT` holding roughly 65 MB of unread replies. `wsl --shutdown` cleared it for a few hours, then the loop returned.
  • Workaround now in `%USERPROFILE%\.wslconfig`: `networkingMode=mirrored`, `dnsTunneling=true`, `localhostForwarding=true`, and `hostAddressLoopback=true`. After `wsl --shutdown`, WSL 3.0.3 / kernel 6.18.54 came up with the host adapters visible (GlobalProtect and the home NIC). This session has had no Management timeouts, and `wslrelay.exe` is no longer on the connection.