Skip to content

[Bug]: SSH environment stays reconnecting after desktop update reuses an older remote server #16984

Description

@kevingatera

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

This is the sequence observed on my setup; I haven't reproduced it from a clean installation.

  1. Connect to an SSH environment using 0.0.46-nightly.20261004.2652.
  2. Leave the remote T3 server running.
  3. Update the desktop to 0.0.46-nightly.20261007.2787.
  4. Open the existing SSH environment.

Expected behavior

The existing environment reconnects. If the remote server needs an update, T3 handles that safely or explains what action is required.

Actual behavior

The environment stayed on “ is reconnecting” (host name redacted). SSH and the forwarded HTTP server were reachable, but the desktop's pairing-token exchange returned HTTP 500.

The October 7 runtime was already installed remotely, while the process serving the SSH environment was still running the October 4 build. The UI didn't explain the authentication failure.

Impact

Blocks work completely in the affected remote environment.

Version or commit

Desktop: 0.0.46-nightly.20261007.2787

Remote server still running: 0.0.46-nightly.20261004.2652

Environment

Linux desktop and Linux SSH server, SSH over Tailscale.

Logs or stack traces

DesktopSshEnvironmentRequestError:
[ssh_http:500] SSH remote API request failed during bootstrap-bearer-session.

Remote server:
reason: 'access_token_issuance_failed'
cause:
  ServerAuthBootstrapCredentialValidationError
  BootstrapCredentialConsumeAvailableError

Workaround

After backing up the database and checking for active provider sessions, I restarted only the remote T3 server using 0.0.46-nightly.20261007.2787, keeping the same base directory and port.

The desktop then reconnected successfully. Live RPC requests succeeded, the reconnecting message disappeared, and the existing chat history remained visible.

This points to reuse of the older server as the trigger, though I haven't isolated the underlying token-consumption failure.

Related reports

Activity

  1. juliusmarminge commented on Oct 7, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the detailed report. Your logs point to a specific mechanism in the code. When the desktop and the reused remote server are on different builds, the pairing token is minted by one build and redeemed by the other. Reading the code, an Oct 4 server can't read tokens minted by an Oct 7 build.

    What the reconnect does (main @ 300f7f9)

    1. The launch script runs the runner once, which installs the desktop's pinned archive version. That's why the Oct 7 runtime showed up on the remote (tunnel.ts#L568-L573).
    2. If ~/.t3/userdata/server-runtime.json names a live server whose port answers the readiness probe, that server is adopted as external and reused. Nothing compares its version to the desktop's (tunnel.ts#L630-L672). Only the managed branch restarts a server when the runner script changes (#L673-L686).
    3. The pairing token is then minted by running auth pairing create --base-dir ~/.t3 through the new runner. It is written to the shared database, not issued by the running server (tunnel.ts#L723-L734, #L1689-L1697). It gets the default AuthStandardClientScopes (cli/auth.ts#L85-L104).

    Why the Oct 4 server returns 500

    This was confirmed by reading the code. I haven't reproduced it end to end.

    Not #16797. The boolean bind (${requestedScopes === undefined}) arrived with #10298 and isn't in the Oct 4 query (AuthPairingLinks.ts @ 4ee6bfd). The Oct 7 server that worked for you does have it.

    Why the UI only says "reconnecting": every SSH preparation failure that isn't a cancellation, including this 500, is mapped to ConnectionTransientError("remote-unavailable") (platform.ts#L170-L182). That error goes into backoff, and backoff shows as reconnecting (presentation.ts#L45-L50). The chat banner title is just " is reconnecting" (ChatView.tsx#L3118).

    Fix direction

    • Detect a version mismatch on reuse. Compare the reused server's version with the runner's archive version. Then either restart it on the matching build or block with a clear "remote server is X, desktop expects Y" message. Avoid killing busy servers ([Bug]: SSH reconnect kills a busy remote server, cancelling all running agents (2s reuse probe) #16477).
    • Alternatively, mint the token through the running server, or request only scopes it understands, so the issuer and consumer always agree.
    • Forward compatibility: drop unknown scope strings when decoding stored grants instead of failing. That prevents the next scope addition from causing a 500 on older servers, though it can't fix builds already shipped.
    • Treat a 5xx from bootstrap-bearer-session as a blocking error that shows the reason, not a silent transient retry.

    Workaround: restart the remote T3 server on the build that matches the desktop. That's what you did, keeping the same --base-dir and port.

    Related: #16797 / #16730 (a different consume-query failure), #16477, #5749, #13341 and #13521 (SSH reuse/restart behavior; more reuse means more chances of version skew), #13717 and #11287 (other ways to get stuck reconnecting).

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions