SSH tunnel readiness times out when unreachable addresses delay the ssh connection past 20s#33531

opened1d agobyGgordysc

What happened

The desktop app cannot connect to an SSH environment. The app retries and fails each time with Timed out waiting 20000ms for backend readiness. The remote server is healthy, and ssh to the same alias succeeds.

Diagnosis

The SSH alias resolves to 3 IPv6 addresses and 1 reachable Tailscale IPv4 address, and ssh tries the IPv4 address last. One IPv6 address fails at once. The other 2 each use the full ConnectTimeout=10, so ssh connects at 20.0s.

The tunnel readiness limit is also 20s. The limit includes the ssh connection time, so the tunnel misses it by about 0.2s.

  • ConnectTimeout=10: packages/ssh/src/command.ts:115
  • SSH_READY_TIMEOUT_MS = 20_000: packages/ssh/src/tunnel.ts:49

Both values are the same on main. With ConnectTimeout=10, 2 unreachable addresses before the reachable address are enough to cause this failure.

The failure log has no sign of the cause. It reports processRunning: true and localPortListening: false. The log tail step then also fails, because its own ssh connection has a 10s limit.

Steps to reproduce

  1. Use a host name that resolves to 2 or more unreachable addresses before a reachable address.
  2. Add the host as an SSH environment in the desktop app.
  3. Connect to the environment.
  4. Run ssh -vv -o ConnectTimeout=10 <alias> true to see the delay for each address.

Version

0.1.7 (desktop app and remote server). The tag and main have the same timeout values.

Environment

  • Client: T3 Code (Beta) desktop app, macOS arm64
  • Remote: Linux x64, t3code.service as a systemd user service
  • Transport: Tailscale SSH, with ssh alias over port 22
  • Remote server kind: external, port 3773

Evidence

shell
10.0 connect to fe80::<redacted>: No route to host
2 0.0 connecting to 2600:<redacted-1>
310.0 connect to 2600:<redacted-1>: Operation timed out
410.0 connecting to 2600:<redacted-2>
520.0 connect to 2600:<redacted-2>: Operation timed out
620.0 connecting to 100.x.x.x
720.0 Connection established
8
9
10With `ControlMaster=no`, `ControlPath=none`, `ConnectTimeout=10`:
11
12| Test | Result |
13|---|---|
14| `ssh <alias> true` (3 runs) | 20.1s each |
15| `ssh -4 <alias> true` | 0.1s |
16| T3 tunnel command, until HTTP 200 | 20.2s |
17| The same command with `AddressFamily inet` | 0.2s |
18
19
20ssh.tunnel.ready.failed
21 processRunning: true
22 localPortListening: false
23 remotePort: 3773
24 remoteLogTailError: SSH command timed out after 10000ms.
25 cause: Timed out waiting 20000ms for backend readiness at http://127.0.0.1:<port>/.

#7733 has the same readiness error but a different cause. In #7733 the local port listens and the HTTP probes exceed 1s. In this issue ssh does not connect inside the readiness limit, and the local port does not listen.

Fix applied or workaround

Add AddressFamily inet under the Host entry in ~/.ssh/config. After this change, ssh connects in 0.1s and the T3 tunnel command gets HTTP 200 in 0.2s.

Filed by

Claude Code (Claude Opus 5.5), via t3 triage.

[GPT-6.1 Sol][Codex] on behalf of shivam.

Reproduced in the Linux desktop app built from e85e0094dd4617a1eada1ad7961f2132a79e67b2, through Settings → Environments → Add Environment. The fixture uses real OpenSSH and a real isolated T3 server; a launcher delays the forwarding process by 21 seconds before executing SSH. This controls the delay rather than reproducing the reporter's DNS/address ordering.

The UI fails with Timed out waiting 20000ms; the desktop log reports processRunning: true and localPortListening: false. A focused regression fails with the 20s budget and passes with a separate 60s-budget change at 7db63c0c45f04b36efe708e8d7743bfbfa781f78 (12 tests passed). The fixed desktop build and macOS remain unverified.

Julius has taken this over in https://github.com/pingdotgg/t3code/pull/33554, so I am stopping the separate branch and handing off these findings.

Linux desktop failure, with test data only:

Recording includes retrying Add environment and the resulting timeout: Linux desktop reproduction