Skip to content

Renaming an SSH connection leaves its remote server unmanaged, so desktop updates never replace it #24095

Closed

Description

@Gooder24

What happened

The SSH connection's alias had been changed. After that, the remote server the desktop had launched for it stayed on its old version through desktop updates. Once the desktop moved to a release whose CLI writes a different database (0.0.45 → 0.1.0), every reconnect failed with Could not prepare the SSH environment … [ssh_http:401] … bootstrap-bearer-session.

This is the part of #21681 that its closing comment left open and asked to file separately: a managed server can still be adopted as external after the SSH alias changes.

Diagnosis

The launcher records which server it owns under ~/.t3/ssh-launch/<state key>. The key hashes the connection's alias, host, user, and port, so editing any of them gives the connection a new key. On the next launch, the new key finds the running server through the default home's server-runtime.json. Its own state directory has no record of that server, so REMOTE_LAUNCH_SCRIPT in packages/ssh/src/tunnel.ts adopts it as external. The old key still records it as managed with its PID, but nothing launches under the old key anymore.

The update path, which replaces the server when the runner changed, applies only to managed servers. An external server therefore stays on the version that started it, and pairing then runs through the desktop's newer runner against that older server.

Steps to reproduce

In the app:

  1. Connect an SSH environment and let the desktop launch the remote server.
  2. Change the connection's alias, user, or port, then reconnect. The launch now reports remoteServerKind: "external".
  3. Update the desktop to a release with a different runner, then reconnect. The old server keeps running, and it is never replaced.

Deterministic version, using the launch script built from main at 24c063a. It runs under sh against a fake t3 serve that writes server-runtime.json, in a throwaway HOME:

  1. Launch under state key old-alias. It starts a server and records it as managed.
  2. Launch under state key new-alias. The result is "serverKind":"external". new-alias records external, while old-alias keeps managed and the PID.
  3. Change the recorded runner and launch under new-alias again. The original server is not replaced.

Version

Desktop 0.1.0, with the remote server at 0.0.45, launched by an earlier desktop. It still reproduces on main at 24c063a.

Environment

The desktop runs on Arch Linux under Wayland. The remote is Ubuntu 24.04 x64 with the release-archive runtime. The deterministic repro ran on Debian 13 with dash as sh and Node 24.21.

Evidence

# Desktop, after the alias change and the desktop update
ssh.environment.ensure.succeeded { remotePort: 3773, remoteServerKind: "external", issuedPairingToken: true }
DesktopSshEnvironmentRequestError: [ssh_http:401] SSH remote API request failed during bootstrap-bearer-session.

# Launch script from main, steps 1-3 above
launch as old-alias:   {"remotePort":34259,"serverKind":"managed"}
launch as new-alias:   {"remotePort":34259,"serverKind":"external"}
  old-alias: managed=managed pid=401160
  new-alias: managed=external pid=-
runner changed, launch as new-alias: {"remotePort":34259,"serverKind":"external"}
  original server 401160: alive, still serving

Related issues

#21681 is closed; this issue is the part its closing comment asked to file separately. #17550 covers the pairing side. It is still open, not merged, so the 401 itself also still reproduces on main. I have a fix for this part rebased on main (an earlier version was #21892, now closed) and can open a PR if you want one.

Fix applied or workaround

On the affected host, I stopped the old server, moved the stale statev2.sqlite* aside, and let the desktop relaunch. Until a fix lands, any later alias, user, or port edit can strand the server again.

Filed by

Claude Opus 5.5 in Claude Code, run from T3 Code.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions