[Bug]: Tailscale Serve failures are only logged as a warning; the server silently stays loopback-only#16238

opened16d agobyRrubenmeza

Before submitting

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

Area

apps/server

Steps to reproduce

  1. On Linux, as a user who is not the Tailscale operator (or on a tailnet with HTTPS certificates disabled), run t3 serve --tailscale-serve.
  2. Watch the output and try to reach the server from another tailnet device.

Expected behavior

When Tailscale Serve was requested and fails, the failure is visible: an error with the reason and a remedy (for example "not the Tailscale operator: run sudo tailscale set --operator=$USER"), surfaced in the CLI output, t3 service status and Settings → Connections, ideally with retry.

Actual behavior

The server starts normally, listens on 127.0.0.1 only, and is unreachable from the tailnet. The only trace is a log warning; there is no retry and no user-visible signal.

From the 0.0.45 bundle: src/server.ts wraps ensureTailscaleServe(...) in catch_(cause => logWarning("Failed to configure Tailscale Serve", ...)).pipe(as(null)). By contrast, t3 pair --tailscale fails loudly in the same situation (TailscaleServeFailedError).

Impact

Major degradation or frequent failure

Version or commit

0.0.45 (t3code-bin 0.0.45-1, Omarchy package)

Environment

Omarchy 4.0.4 (Arch), Linux 7.2.5, tailscale 1.102.3

Logs or stack traces

shell
1Failed to configure Tailscale Serve

Workaround

Run sudo tailscale set --operator=$USER once, make sure MagicDNS and HTTPS certificates are enabled for the tailnet, then restart the server.

Related

The missing way to enable Serve for t3 service install is proposed separately in Ideas: #16243

Synced from GitHub

Same failure in the macOS desktop app, plus a second bug that stops it from recovering.

Steps

  1. On a tailnet with HTTPS certificates disabled, turn on Tailscale HTTPS (port 443) in Settings → Connections and confirm.
  2. The backend relaunches and tailscale serve fails. tailscale cert returns "your Tailscale account does not support getting TLS certs". The switch shows off, and desktop-settings.json now has "tailscaleServeEnabled": true.
  3. Enable HTTPS certificates in the Tailscale admin console.
  4. Turn the switch on and confirm Setup again. The dialog closes and nothing else happens. There is no relaunch and no tailscale serve call, and the switch stays off.

The dialog says T3 Code will restart the local backend, but setTailscaleServeEnabled returns requiresRelaunch: result.changed (apps/desktop/src/backend/DesktopServerExposure.ts:532 on d7202109). The saved flag and port already match from step 1, so nothing relaunches. The server calls ensureTailscaleServe only at startup (apps/server/src/server.ts:781), so Serve stays off until the user quits and reopens the app. Quitting and reopening fixed it here.

#14746 hits the same no-op relaunch in its DNS case. #15027 changes which state the switch reads but not the relaunch, so after it lands, step 4 would show the switch already on with a health note, and the only way to retry would be to turn it off and on again.

A possible fix is to relaunch whenever the user confirms Enable, for example requiresRelaunch: result.changed || input.enabled, which matches what the dialog says.

T3 Code 0.0.46-nightly.20261007.2787, macOS 26.5, Tailscale 1.102.4.

Reproduced on Linux at main b5a226e49c with the real server and Tailscale 1.104.1, running as a non-operator. Started serve --tailscale-serve --tailscale-serve-port 18443 --port 18638 --host 127.0.0.1 against an isolated data directory. Tailscale exited 1 with permission-denied; T3 logged WARN: Failed to configure Tailscale Serve, then printed T3 Code server is ready and Connection string: http://127.0.0.1:18638. The listener stayed on loopback and tailscale serve status --json returned {}. No duplicate found among the open issues.

The startup fix needs a maintainer decision: the same Serve layer runs in CLI and desktop modes. Making all failures fatal can prevent desktop users from reaching the persisted setting that disables Serve; preserving desktop recovery requires mode-specific behavior. Stopped under the triage hard stop on runtime-mode changes. No fix was committed or pushed. Sanitized runtime transcript.

Confirmed again on Linux at main a50cd989ae, using the real server with serve --tailscale-serve --tailscale-serve-port 18443 --port 18638 --host 127.0.0.1 and isolated data. Tailscale returned permission-denied; T3 printed a warning followed by “T3 Code server is ready,” with only a loopback listener and no Serve mapping. Sanitized runtime transcript. No duplicate found among 916 open issues.

Synced from GitHub

Another common way to hit this on macOS with no misconfiguration at all: a login race after reboot. Because Serve is set up once and never retried, the mapping stays off until T3 Code is restarted.

Desktop 0.1.2-nightly.20261021.3473, Tailscale 1.104.2 (standalone Tailscale.app), tailscaleServeEnabled: true:

TimeEvent
13:29:44Shutdown: the acquireRelease finalizer runs tailscale serve --https=443 off (succeeds)
13:30:18Mac boots
13:32:45T3 Code (opened at login) runs ensureTailscaleServe → tailscale serve exited with code 1, logged as Failed to configure Tailscale Serve
13:32:46Tailscale.app process starts, one second later

Afterwards tailscale serve status reports No serve config, the desktop probe of https://<node>.ts.net/.well-known/t3/environment fails with a transport error, and the mobile app cannot connect. Running tailscale serve --bg --https=443 http://127.0.0.1:3773 by hand, or quitting and reopening T3 Code, fixes it.

Because the finalizer always removes the mapping on quit, a single failed attempt at startup always leaves Serve off. Retrying ensureTailscaleServe with backoff while the setting is on (or re-running it when the desktop's existing probe sees the endpoint is down) would cover this case without the fatal-vs-recoverable question raised above.