Repository navigation
Description
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:
- Connect an SSH environment and let the desktop launch the remote server.
- Change the connection's alias, user, or port, then reconnect. The launch now reports
remoteServerKind: "external". - 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:
- Launch under state key
old-alias. It starts a server and records it asmanaged. - Launch under state key
new-alias. The result is"serverKind":"external".new-aliasrecordsexternal, whileold-aliaskeepsmanagedand the PID. - Change the recorded runner and launch under
new-aliasagain. 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 servingRelated 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.
Activity