[Cowork/Desktop] Device bridge flaps on a strict 2-hour cycle when the machine is unattended; bridge timers fire minutes late; cloud sessions stay unbound until user logs in over RDP

Status Open
Reported on v2.1.284
Maintainer reply None cached
Activity 1 comment · opened Sep 30, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

This is about the Claude desktop app's Cowork device bridge (remote-tools-device), not the CLI; filing here because earlier bridge issues (#77385, #91111, #96918, #90874) live in this repo.

Environment

  • Claude desktop for Windows (MSIX): 2.9939.4 → auto-updated to 2.16120.0 on 2026-09-30; behaviour identical on both
  • Windows 10 Pro, always-on server, wired LAN, no proxy (WinHTTP direct, no PAC)
  • The app runs in the user's interactive session, normally reached over RDP from a LAN client. Cloud Cowork sessions and cloud scheduled tasks use this machine through the device bridge.
  • Claude Code (claude remote, several instances) runs on the same host, same user, same network, throughout; it never lost connectivity during any of the events below.

Symptom

Cloud sessions bound to this device fail with Device '<device>' disconnected before responding. and The device this session is bound to is not connected to the bridge., for 10–60 minutes at a time, many times per day. Reloading the session's tools (ToolSearch) does not recover it. Recovery coincides with the user logging in over RDP; otherwise it recovers on its own after the episode ends.

What the app's own log shows (%LOCALAPPDATA%\Claude\Logs\main.log)

Every episode is the same loop: pong timeout (1 consecutive) — resetting → reconnect #N in <1–18 s> → connecting wss://bridge.claudeusercontent.com → handshake timeout → repeat, until an authenticated finally sticks. The sessions-bridge poller logs Poll error, backing off: This operation was aborted at the same moments.

The reconnect timers fire minutes late. Example, 2026-09-29 (local time):

| logged | planned delay | connecting actually logged | late by |
|---|---|---|---|
| 21:36:26 reconnect #1 in 1872ms | 1.9 s | 21:39:23 | ~3 min |
| 21:43:41 reconnect #4 in 3809ms | 3.8 s | 21:45:05 | 84 s |
| 21:48:05 reconnect #7 in 13169ms | 13 s | 21:49:03 | 58 s |

Handshake timeouts are likewise logged 60–80 s after the connect attempt. Over 9/27–9/30, 274 of 747 reconnect timers fired ≥20 s late (max 315 s). Outside episodes, timers fire on time.

Strict two-hour cadence

Reconnects per hour (count / timers ≥20 s late, worst lateness), four consecutive nights:

09-28 01h 18/6 315s   03h 26/10   05h 33/13   07h 36/12   09h 35/12      (00h 3/0, 02,04,06,08h: none)
09-29 01h 28/9 193s   03h 28/15   05h 29/7    07h 19/10   09h 24/9       (00h 2/0, 02,04,06,08h: none)
09-30 01h 18/8 214s   03h 21/11   05h 24/7    07h 18/10   09h 21/8  11h 29/9   (00,02,04,06,08,10,12h: 0–1)

Each episode starts at ~:06–:12 past the odd hour and ends ~:58. During the day, with the user intermittently present, episodes are irregular but still frequent. The connection was clean from 2026-09-25 through 2026-09-27 10:59; the pattern began at 11:00 on 9/27 and has not stopped.

Ruled out on the client side

  • Network path: a 10-second probe (DNS, TCP, TLS to bridge.claudeusercontent.com, api.anthropic.com, claude.ai, www.google.com, 1.1.1.1) ran alongside for 20+ hours: 353–359 rounds/hour, no gaps, TLS 6–20 ms, only isolated single-round blips. Clean throughout every app episode, so host, NIC, DNS and path were healthy while the app's socket was timing out.
  • RDP state: episodes occur with the session connected, disconnected (event 24, reason 0), and after tscon <id> /dest:console put the session on the physical console for a full night (identical histogram).
  • Proxy/PAC: none. Disk/CPU/memory: nothing in the System log correlates; single-instance app (one main process). Load: episodes occur at idle.
  • Windows scheduled tasks: none at the odd-hour cadence.

Second failure: session binding does not follow the device

At 2026-09-30 10:35 ET one cloud session executed device_bash on this machine successfully while a second cloud session, bound to the same device, was still failing with "not connected to the bridge" after tool reloads, and had been since 02:31Z. The second session started working immediately when the user connected over RDP at ~13:15 ET. Each app reconnect logs a fresh connect frame sent: device_id keyless (row_pk_enclave); it looks like a session bound before a re-registration does not see the new one.

What Should Happen?

The desktop app should keep its bridge connection up while the machine is unattended (RDP client closed, client asleep, or session on the physical console), the same way Claude Code on the same host does. Reconnect timers should fire when scheduled, not 1–5 minutes late. A cloud session bound to the device should reach it whenever any other session can, and should re-bind after the device re-registers without requiring the user to log in interactively.

Error Messages/Logs

Cloud session side:
Device '<device>' disconnected before responding.
The device this session is bound to is not connected to the bridge.

Desktop app main.log, one episode (2026-09-29, local time; note the gaps between "reconnect #N in Xms" and the following "connecting"):
2026-09-29 21:35:27 [error] [sessions-bridge] Poll error, backing off: This operation was aborted
2026-09-29 21:36:26 [info] [remote-tools-device] pong timeout (1 consecutive) — resetting
2026-09-29 21:36:26 [info] [remote-tools-device] reconnect #1 in 1872ms
2026-09-29 21:39:23 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:39:23 [info] [remote-tools-device] cannot send (socket not open): response
2026-09-29 21:39:31 [info] [remote-tools-device] connect frame sent: device_id keyless (row_pk_enclave)
2026-09-29 21:39:31 [info] [remote-tools-device] authenticated
2026-09-29 21:39:31 [info] [remote-tools-device] replies redelivered=0 resent=0 expired=1 dropped=0
2026-09-29 21:40:00 [info] [remote-tools-device] pong timeout (1 consecutive) — resetting
2026-09-29 21:40:00 [info] [remote-tools-device] reconnect #1 in 1995ms
2026-09-29 21:40:00 [info] [remote-tools-device] keep-awake released (quiet, held 2705906ms)
2026-09-29 21:40:12 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:41:34 [info] [remote-tools-device] handshake timeout
2026-09-29 21:41:34 [info] [remote-tools-device] reconnect #2 in 1595ms
2026-09-29 21:41:36 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:41:45 [info] [remote-tools-device] connect frame sent: device_id keyless (row_pk_enclave)
2026-09-29 21:42:54 [info] [remote-tools-device] handshake timeout
2026-09-29 21:42:54 [info] [remote-tools-device] reconnect #3 in 2026ms
2026-09-29 21:43:02 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:43:41 [info] [remote-tools-device] handshake timeout
2026-09-29 21:43:41 [info] [remote-tools-device] reconnect #4 in 3809ms
2026-09-29 21:45:05 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:46:12 [info] [remote-tools-device] handshake timeout
2026-09-29 21:46:12 [info] [remote-tools-device] reconnect #5 in 4150ms
2026-09-29 21:46:21 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:46:49 [info] [remote-tools-device] handshake timeout
2026-09-29 21:46:49 [info] [remote-tools-device] reconnect #6 in 7120ms
2026-09-29 21:46:56 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:48:05 [info] [remote-tools-device] handshake timeout
2026-09-29 21:48:05 [info] [remote-tools-device] reconnect #7 in 13169ms
2026-09-29 21:49:03 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:49:23 [info] [remote-tools-device] handshake timeout
2026-09-29 21:49:23 [info] [remote-tools-device] reconnect #8 in 18340ms
2026-09-29 21:49:41 [info] [remote-tools-device] connecting wss://bridge.claudeusercontent.com
2026-09-29 21:49:41 [info] [remote-tools-device] connect frame sent: device_id keyless (row_pk_enclave)
2026-09-29 21:49:41 [info] [remote-tools-device] authenticated
2026-09-29 21:52:04 [info] [remote-tools-device] keep-awake held (pss=0)

(sessions-bridge "Poll error, backing off" lines interleave at 21:39:23, 21:41:34, 21:42:54, 21:43:41, 21:46:12, 21:46:49, 21:49:03 with backoff attempts 1–6.)

Steps to Reproduce

  1. Windows 10 Pro machine, Claude desktop (MSIX) running in the user's interactive session, signed in, Cowork enabled, at least one folder connected.
  2. Start a cloud Cowork session (or a cloud scheduled task) that uses device_bash / file tools on that machine, e.g. a job that calls the device every few minutes for an hour or more.
  3. Connect to the machine over RDP from a LAN client, then close the RDP client (or let the client sleep, or run tscon <id> /dest:console). Leave the machine unattended.
  4. Watch %LOCALAPPDATA%\Claude\Logs\main.log for remote-tools-device lines. Within the next odd hour (~:06 past) the pong-timeout / reconnect / handshake-timeout loop starts and runs ~50 minutes; reconnect timers fire 1–5 minutes after their logged delay.
  5. During the episode the cloud session's device calls fail with the two errors above; reloading tools does not help.
  6. Log in over RDP: the cloud session's next call succeeds immediately.

Per-hour histogram used for the cadence (PowerShell, read-only):
$rows=@(); $pend=$null; foreach ($l in (Get-Content "$env:LOCALAPPDATA\Claude\Logs\main.log")) { if ($l -match '^(\S+ \S+) .remote-tools-device\] reconnect #\d+ in (\d+)ms') { $pend=@{t=[datetime]$matches[1]; ms=[int]$matches[2]} } elseif ($pend -and $l -match '^(\S+ \S+) .remote-tools-device\] connecting wss') { $t=[datetime]$matches[1]; $rows += [pscustomobject]@{At=$pend.t; Late=[math]::Round(($t-$pend.t).TotalSeconds-$pend.ms/1000)}; $pend=$null } }; $rows | Group-Object { $_.At.ToString('MM-dd HH') } | ForEach-Object { '{0}h reconnects={1} late20+={2} maxLate={3}s' -f $_.Name,$_.Count,@($_.Group|Where-Object{$_.Late -ge 20}).Count,($_.Group|Measure-Object Late -Maximum).Maximum }

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

Desktop 2.9939.4 was clean until 2026-09-27 10:59 and broken from 11:00 the same day, so unclear whether it is a client version or a service-side change

Claude Code Version

Desktop app 2.16120.0 (MSIX, Windows), previously 2.9939.4; bundled CLI 2.1.284

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other

Additional Information

Questions

  1. What runs on a 2-hour cycle in the bridge client or service (credential rotation? keep-awake?) that would explain odd-hour-only episodes?
  2. Does the bridge client run in a renderer/web-contents context subject to Chromium timer throttling? The multi-minute timer lateness looks like it. Currently testing a launch with --disable-background-timer-throttling --disable-renderer-backgrounding --disable-backgrounding-occluded-windows --disable-features=IntensiveWakeUpThrottling,CalculateNativeWinOcclusion (via Invoke-CommandInDesktopPackage); will report the result here.
  3. Why does a bound cloud session not re-bind after the device re-registers, when another session can reach the device at the same time?

Notes on the template fields

  • "Claude Code Version" below is the bundled CLI the desktop app runs (%APPDATA%\Claude\claude-code\2.1.284\claude.exe); the bug is in the desktop app/bridge, not the CLI.
  • Regression: the same machine had a clean bridge connection 2026-09-25 through 2026-09-27 10:59 (1–2 reconnects/hour, none late) on desktop 2.9939.4; the pattern began 2026-09-27 11:00 with no local change identified, and persists on 2.16120.0.

Available on request

Full main.log excerpts for any window, the network probe CSV, the RDP session event log (TerminalServices-LocalSessionManager 24/25/40), and the histogram script above.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗