Skip to content

[Bug]: Desktop does not recover network access when Tailscale connects after launch #17362

Open

Description

@jgoyvaerts

Before submitting

  • Searched existing issues. Related reports are linked below; none found covers the saved Network access preference staying inactive after Tailscale connects later.
  • Included the reported sequence, observed configuration, and source analysis.

Area

apps/desktop — Settings → Connections and local backend startup.

Summary

If Tailscale is not connected when T3 Code starts, connecting it after the desktop app is already running does not reliably restore the previously enabled network/Tailscale access. Settings shows Network access off and “Limited to this machine,” even though the saved preference is still enabled. View → Reload does not recover it.

The reporter says restarting T3 Code after Tailscale is connected restores access. This should recover without requiring a restart of the local backend and potentially interrupting running agents.

Steps to reproduce

Reported sequence:

  1. Previously enable Network access in the desktop app. Tailscale HTTPS was also enabled in this instance.
  2. Launch T3 Code while Tailscale is disconnected/not yet available.
  3. Connect Tailscale after T3 Code is already running.
  4. Open Settings → Connections for the local environment.
  5. Network access remains off and says “Limited to this machine.” Tailscale HTTPS also remains off.
  6. Use View → Reload. The access state still does not recover.
  7. According to the reporter, quitting and reopening T3 Code with Tailscale already connected restores access.

Important reproduction condition from the source: the startup fallback requires no usable LAN address and no Tailscale IPv4 address at startup. Tailscale being disconnected alone should not trigger that fallback if a usable LAN address is already present. The original startup interface snapshot was not captured, so this condition is a likely explanation to verify rather than an independently reproduced fact.

Expected behavior

Previously enabled Network access should remain effective, or recover when the required networking becomes available, without requiring a manual app restart.

If Tailscale HTTPS setup cannot complete at startup, its saved preference and setup failure should remain visible, with a way to retry when Tailscale connects.

Actual behavior and diagnostics

The screenshot supplied by the reporter shows:

  • Local environment enabled.
  • Network access off, with “Limited to this machine.”
  • Tailscale HTTPS off, with the setup description.
  • Desktop/server version 0.0.46-nightly.20261007.2774.

Read-only inspection of this instance found:

{
  "savedPreferences": {
    "serverExposureMode": "network-accessible",
    "tailscaleServeEnabled": true,
    "tailscaleServePort": 445
  },
  "runningBackend": {
    "host": "127.0.0.1",
    "port": 3773
  }
}

Tailscale CLI diagnostics at the same investigation point showed:

  • BackendState: Running.
  • This machine online, with a MagicDNS name and tailnet addresses.
  • No Tailscale health warnings.
  • tailscale serve status --json returned {}: no Serve forwarding configured.

Thus this is more than a stale endpoint label: the backend is actually bound to loopback while the saved Network access preference remains enabled. The missing HTTPS mapping is an additional observed symptom of the late-connect sequence.

Code investigation

Source inspected: main @ d81afa0a6f403bd6e5562ffcee2484089a1fdc3f.

  • DesktopServerExposure.resolveRuntimeState falls back to local-only when the requested mode is network-accessible but no usable LAN or Tailscale IPv4 address is found. It preserves the requested preference.
  • DesktopApp startup calls configureFromSettings before starting the backend.
  • getAdvertisedEndpoints reads current interfaces but retains the previously resolved exposure state; it does not restore the backend binding.
  • The existing fallback test explicitly verifies loopback binding while the saved preference remains network-accessible. Recovery after interfaces become available is the missing behavior.
  • Tailscale Serve setup runs at backend startup and catches setup failures as warnings; no retry for a later Tailscale connection was found.

Related issues

The primary missing behavior in this report is recovery of saved network access after networking/Tailscale becomes available during an existing desktop session.

Impact

Minor bug or occasional failure. Remote access stays unavailable until a restart, and restarting a desktop-hosted backend can interrupt agents, terminals, and remote clients.

Version or commit

T3 Code Nightly 0.0.46-nightly.20261007.2774; source analysis against main at d81afa0a6f403bd6e5562ffcee2484089a1fdc3f.

Environment

macOS 26.6.2, Apple Silicon (arm64), desktop-hosted backend, Tailscale connected after launch.

Workaround and verification limits

The reporter identifies restarting T3 Code with Tailscale already connected as the workaround. View → Reload did not help.

Investigation used the supplied screenshot, read-only configuration/diagnostics, and source inspection. No controlled launch/reconnect reproduction, app restart, settings edits, or manual Serve configuration was performed during the investigation. Private hostnames, tailnet addresses, credentials, and raw logs are omitted.

Activity

  1. juliusmarminge commented on Oct 8, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the detailed write-up. I checked this against current main (6308db4) and read the code only; I didn't reproduce it.

    What the code does

    • At launch, configureFromSettings runs once, before the backend starts (DesktopApp.ts#L225-L252). If Network access is saved as on but there's no usable IPv4 address, resolveRuntimeState falls back to binding 127.0.0.1 and keeps the saved preference. That fallback is deliberate and tested. Any non-loopback, non-link-local, non-Tailscale IPv4 address counts as LAN (L68-L71), so the fallback most likely needs no network at all at launch (for example, launching at login before Wi‑Fi is up), not just Tailscale being down. That matches your caveat.
    • Nothing re-resolves exposure after launch. DesktopNetworkInterfaces only does a one-shot os.networkInterfaces() read with no watcher, and getAdvertisedEndpoints reads current interfaces only to list endpoints; it doesn't change the bind host. So View → Reload can't help.
    • Settings shows the effective mode, not the saved one. toContractState sends mode: state.mode, and the switch and the "Limited to this machine." text (L3198-L3201, L3617) can't tell "off" apart from "on, but no network address at launch". The bootstrap warning (DesktopApp.ts#L234-L240) only goes to the log.
    • Turning Network access back on in Settings probably works as an in-app retry, but it isn't a no-restart one. setMode re-reads interfaces, and because the bind host changes, requiresRelaunch is true, so the IPC handler calls lifecycle.relaunch, which relaunches the whole app ("Restart and enable", L3840-L3865). That's effectively the same as quitting and reopening.
    • Tailscale HTTPS: Serve is configured once at backend startup, and a failure is only logged as a warning with no retry (server.ts#L758-L790). The switch reflects the endpoint probe (L3559), so it shows off. Confirming Setup again likely does nothing, because setTailscaleServeEnabled only asks for a relaunch when the saved setting changes. This part matches #16238 (including the macOS follow-up there) and #14746.

    Possible fix directions (not decided)

    Rebinding from 127.0.0.1 to 0.0.0.0 means restarting the backend, which can interrupt running agents. So fully automatic recovery is partly a design choice: auto-restart when an address shows up, prompt the user, or bind wider up front and filter. Smaller pieces that seem to avoid that choice:

    1. Expose the saved (requestedMode) mode next to the effective one, so Settings can say something like "Network access is on, but no network address was available at launch", with a Restart/Retry action instead of a plain off switch.
    2. Retry ensureTailscaleServe without restarting the backend. Serve forwards to 127.0.0.1 (L774), so HTTPS access may be recoverable even while the backend is loopback-only. Also make Setup re-run Serve when the setting is already on, which is the #16238 / #14746 half.

    Related

    • #16238: Serve failures aren't retried or surfaced. This overlaps the HTTPS half.
    • #14746 / PR #15027: HTTPS switch state follows the probe (web only).
    • #15751 / PRs #15840, #16026: stale endpoint cache. These refresh what's listed but don't rebind, so they likely don't fix this.

    As far as I can tell, no open PR re-resolves the bind host or retries Serve after launch.

    Workaround: with the network (and Tailscale) connected, quit and reopen T3 Code, or turn Network access on again in Settings → Connections, which also relaunches the app.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 8, 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