Repository navigation
[Bug]: Connections keeps stale network endpoints after reopening settings #15751
Copy link
Copy link
Labels
bugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
Description
Activity
Note
Grok responding on behalf of Julius.
Triage
Thanks for the precise state-layer probe, @arthurkatcher! It pointed right at the cause.
What I found
Confirmed on
mainat4ee6bfd. This is separate from #15750: the desktop provider reads current interfaces whenever it's called, so this is purely the renderer cache.- Why reopening doesn't refresh.
createDesktopNetworkAccessStateAtom(apps/web/src/state/desktopNetworkAccess.ts) wrapsAtom.swr({ staleTime: 30_000, revalidateOnMount: true })inAtom.keepAlive.staleTimeis only checked when that SWR atom mounts.keepAlivekeeps the wrapper mounted after/settings/connectionsunmounts, so reopening the page just resubscribes to the existing value.- So
revalidateOnMountonly applies to the first load in a session. There's no focus signal or network-change invalidation either.
- Why the existing test misses it. "retains the loaded snapshot when the settings screen remounts" remounts inside the fresh window and never advances time past 30 s.
- When a refresh does happen.
- An explicit
registry.refreshcallsgetAdvertisedEndpointsagain, which matches your probe. refreshDesktopNetworkAccessStateonly runs after changing network exposure or Tailscale Serve (ConnectionsSettings.tsx).- For comparison, SSH host discovery uses the same keep-alive SWR shape but refreshes when its dialog opens.
- An explicit
- Related, not duplicates: [Bug]: Connections shows "Up to date" for this machine while a desktop update is available #14754, Tailscale HTTPS shows off and cannot be disabled in Settings when local DNS fails #14746, [Bug]: Tailscale connect completely broken after recent nightly update #9869, [Bug]: --tailscale-serve leaves headless backend classified as local-only #4462, and [Bug]: Tailscale Serve mapping is hijacked by a secondary instance and left stale on unclean exit, never reconciled #10363.
Likely fix area
Some options:
- Refresh the endpoint atom when entering the Connections route, like the SSH dialog does.
- Change the atom composition so a stale remount actually revalidates (for example,
keepAliveon the source atom rather than the SWR wrapper). - Either way, add a test that advances past 30 s and asserts the bridge is called again.
Watching interfaces live while the page stays open would be a separate change.
A maintainer will decide on the fix direction.
- Why reopening doesn't refresh.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 4, 2026
Metadata
Metadata
Assignees
Labels
bugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
Before submitting
Area
apps/web (desktop Connections settings)
Steps to reproduce
Expected behavior
Reopening Connections after its endpoint snapshot becomes stale should discover the current addresses without restarting the desktop app.
Actual behavior
The previous endpoint list remains cached and the newly available address does not appear. The desktop provider reads current interfaces when invoked, but the frontend state can prevent that new read.
Impact
Minor bug or occasional failure: network changes during a session leave sharing options stale and require a renderer reload or a separate setting mutation to trigger refresh.
Version or commit
Observed while using 0.0.45. State-layer reproduction confirmed on main at
4ee6bfd50ef4a089440d5c3662db2298da9cc50e.Environment
Ubuntu 24.04.4 LTS, T3 Code Desktop; Tailscale connected after the Settings list was loaded.
Investigation
desktopNetworkAccess.ts configures
Atom.swr({ staleTime: 30_000, revalidateOnMount: true })followed byAtom.keepAlive. The wrapper stays mounted across consumer remounts. No focus signal or network-change invalidation is configured. Existing explicit refresh calls are tied to settings mutations.A deterministic isolated probe extracted the production factory and used the repository's installed Effect runtime. The bridge first returned only a LAN endpoint. After changing its response to include Tailscale, advancing
Date.nowby 60,001 ms, and unmounting/remounting the consumer, the cached snapshot and read count were unchanged. Explicitregistry.refresh(atom)loaded the new endpoint immediately.This is state-layer evidence; it is not a recording from a rebuilt Electron client. The separate CGNAT misclassification is not needed to reproduce the stale cache.
Workaround
Use View → Reload to recreate the frontend state. A reload refreshes the list but does not repair incorrect address classification in the endpoint provider.