Skip to content

fix(devices): surface stalled and failed remote desktop connections - #215

Draft
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixremote-desktop-surface-stalled-and-dbc6c3
Draft

fix(devices): surface stalled and failed remote desktop connections#215
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixremote-desktop-surface-stalled-and-dbc6c3

Conversation

@posthog

@posthog posthog Bot commented Aug 12, 2026

Copy link
Copy Markdown

Problem

  • A remote desktop connection failure was a silent dead end: the user got a black rectangle with no error, no retry, and no way out except reloading the page. This is a core, high-traffic flow.
  • The canvas stayed visibility: hidden until the first JPEG tile drew, and the spinner rendered only while !firstFrameReceived && state >= 1. When the relay socket dropped, MeshTunnel reports state 0, so both conditions went false at once and the container showed its plain bg-black.
  • No first-frame timeout: once the handshake reached state 3, nothing re-requested a key frame or reported a failure if the agent never streamed — an eternal "Waiting for desktop stream…".
  • No visibility: nothing in src/lib/meshcentral/ captured an exception, so this whole class of breakage was invisible in error tracking.

Changes

Failure Before After
Relay socket drops before any frame (state 0) Blank black canvas Failed state with reason + Retry button
Agent connects but never streams (state 3) Endless spinner One re-send of the compression/start message, then "The desktop stream did not start."
Connect setup throws Toast only Failed state + Retry + $exception
  • Retry clears the failure and re-runs the connect effect (connectNonce); its cleanup resets initializingRef and stops the dead tunnel, then a fresh tunnel reconnects.
  • The state-0 handler ignores the teardown-emitted state 0 (cancelled guard) so a retry does not re-raise the failure it just cleared. Once a frame has drawn, the canvas keeps its last image and the existing reconnect toasts still apply.
  • Each failure is reported through a new captureException helper (routes to the GTM-loaded window.posthog) with tunnelState and nodeId attached.

Why

The failure path ended in an unrecoverable dead end on a core flow, and the failure rate could not even be measured because the surface emitted no exception or success events.

Test plan

  • npm run type-check passes.
  • biome check clean on the changed files.
  • Live remote-desktop reproduction (relay drop / silent agent) — needs a MeshCentral relay + agent, not available in the sandbox. Verified by tracing each state transition through the new rendering branches.

Notes


Created with PostHog Desktop from this inbox report.

The remote desktop viewer kept the canvas hidden until the first JPEG tile drew
and only rendered the spinner while state >= 1, so a relay socket drop (state 0)
hid both and left a blank black rectangle with no error and no retry.

- Render a retryable failed state when the tunnel reaches state 0 without a
  frame; Retry re-runs the connect effect to reconnect.
- Add a first-frame watchdog on state 3: nudge the agent once by re-sending the
  compression/start message and a refresh, then declare "the desktop stream did
  not start" instead of an endless spinner.
- Capture these failures as PostHog exceptions with the tunnel state and node id
  so the failure is visible in error tracking, not only in a session recording.

Generated-By: PostHog Desktop
Task-Id: dc518b51-454a-4da2-8644-ee81f76aa513
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants