[Bug]: Launching offline deletes saved T3 Connect environments because Clerk loads as signed out#17917

openedOct 10, 2026byJjosephv123

Before submitting

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

Area

apps/web

Steps to reproduce

  1. On desktop, sign in to T3 Connect and save a remote environment whose only route is T3 Connect.
  2. Quit the app.
  3. Turn off Wi-Fi so navigator.onLine is false, or launch right after a reboot before the network is up.
  4. Launch the app.

Expected behavior

Being offline at launch does not change saved environments. The app reconnects once the network returns.

Actual behavior

From reading the code (see Diagnosis), the saved T3 Connect route is removed. An environment with no other route is deleted entirely and does not come back when the network returns. I reproduced the T3 Code half with a test. I have not run the full offline launch end to end.

Diagnosis

1. Clerk loads as signed out while offline. @clerk/clerk-js 6.32.1 BaseResource._baseFetch returns null when a request fails while navigator.onLine is false ("Network request failed while offline, returning null"). The Electron load path (#tg, standardBrowser: false) has no cached-resources fallback, so load() finishes "ready" with an empty client. useAuth() then reports isLoaded: true, isSignedIn: false.

2. T3 Code treats that as a sign-out. In apps/web/src/cloud/managedAuth.tsx, observedAccountRef starts as undefined. On the first loaded render, previousAccount !== null is true, so the signed-out branch calls queueAccountCleanup(). That runs environmentCatalog.removeRelayEnvironments and resets the relay token cache. removeRelayEnvironments (packages/client-runtime/src/connection/registry.ts) removes the relay route from every saved environment. removeRoute then calls removeLocked when no routes remain.

So the first signed-out observation after launch is treated as an account sign-out, even though this session never saw a signed-in account. Clerk can report that state because the device is offline, not because the user signed out.

Reproduction of the T3 Code half, which passes on main (4f63275ac7), using jsdom with @clerk/react mocked:

tsx
1const removeRelayEnvironments = vi.fn(async () => ({ _tag: "Success" }));
2const auth = { getToken: vi.fn(), isLoaded: false, isSignedIn: false, userId: null as string | null };
3vi.mock("@clerk/react", () => ({ useAuth: () => auth }));
4vi.mock("../state/use-atom-command", () => ({ useAtomCommand: () => removeRelayEnvironments }));
5
6await act(async () => root.render(<ManagedRelayAuthProvider>{null}</ManagedRelayAuthProvider>)); // Clerk loading
7auth.isLoaded = true; // Clerk finishes loading signed out (offline launch)
8await act(async () => root.render(<ManagedRelayAuthProvider>{null}</ManagedRelayAuthProvider>));
9
10expect(removeRelayEnvironments).toHaveBeenCalledTimes(1);

Impact

Major degradation or frequent failure

Version or commit

main @ 4f63275ac7; desktop 0.0.46-nightly.20261010.2935

Environment

macOS desktop (Electron) with @clerk/electron 0.0.44, @clerk/react 6.16.1 and @clerk/clerk-js 6.32.1. The web client is probably affected too, if its offline load also ends "ready". I haven't verified that.

Workaround

Avoid launching the app while offline. If environments disappear, sign in again and add them again.

Suggested fix

Run account cleanup only on a transition from a known signed-in account to signed out or another account. In other words, skip it when previousAccount === undefined. A first observation of "signed out" should only leave the relay session inactive.

Related: #15725 (Clerk never loads after a startup network failure) and #11004 (a missing session is reported as "Your cloud sign-in changed"). This is the opposite outcome of the same startup race: Clerk loads, but as signed out, and saved state is deleted.

Classified as a bug, not an exploitable vulnerability. Source inspection at available main b5a226e still shows the initial signed-out observation queuing account cleanup in managedAuth.tsx. No end-to-end offline launch was run; this is not a reproduction result. Checked all 948 open issue titles; no same-symptom duplicate found. #17106 retains the environment but fails to reconnect, a different symptom. A fix changes managed-authentication sign-out handling, which requires maintainer review under the triage rules. Leaving open for Julius.

Synced from GitHub

Adding a recent desktop occurrence and an isolated probe of the installed build. The symptom matches this issue, but I cannot prove that this particular launch was offline or that Clerk emitted a signed-out result during the incident.

What happened

On October 31, 2026, immediately after updating and restarting T3 Code Nightly on macOS, both previously saved remote machines disappeared from the desktop sidebar. The updated local server reports 0.1.6-nightly.20261031.3973.

The missing machines were a home server and another Mac. During investigation:

  • Both machines were still discoverable under the signed-in T3 account, but Settings → Environments showed both as Not added.
  • The home server was online. The separate Linked environments list still showed it as reachable, and listing its threads through the environment tools succeeded.
  • The other Mac's T3 Connect tunnel was offline. This did not explain why the online home server also disappeared from the saved desktop environments.
  • The desktop account panel showed the user signed in when inspected. That observation does not establish the auth state during the earlier restart.

Re-adding both existing machines through Settings → Environments restored the sidebar entries and threads without changing the installed application or databases. The home server connected via a learned Tailscale route. The other Mac's cached threads became visible, although its tunnel remained offline. The home server's thread data was intact.

Local trace evidence

These are selected fields from desktop.trace.ndjson, with machine names, addresses, and local paths omitted. All four operations completed successfully. Times are local, UTC+05:30:

text
12026-10-31 15:18:09.329890 desktop.updates.installDownloadedUpdate Success
22026-10-31 15:18:10.140198 ElectronUpdater.quitAndInstall Success
32026-10-31 15:18:19.826247 desktop.connectionCatalogStore.get Success
42026-10-31 15:18:27.769879 desktop.connectionCatalogStore.set Success

No connection-catalog read/decryption failures were found in the inspected update/startup interval. The successful catalog write about 18 seconds after update installation is evidence of a post-restart rewrite, not proof of deletion: the trace does not include the catalog contents or identify the auth event that caused the write.

Isolated probe of the installed Nightly

The account-transition planner and account-service functions were extracted unchanged from the installed renderer asset runtime-BXOvbSXE.js and evaluated in an isolated Node harness. The async result execution/reporting helpers were replaced with minimal harness helpers, and the lifecycle handlers were spies. No live Clerk session, credentials, connection catalog, or network was used.

Three initial account observations were supplied independently:

text
1user: undefined → state Unobserved; no handler calls
2user: { id: fixture-account } → state Active; activate called; cleanup count 0
3user: null → state SignedOut; deactivate called;
4 cleanUp({ accountId: null, wasActive: false }) called

The preservation assertion for the third case failed:

text
1Expected cleanup count before any observed sign-in: 0
2Actual cleanup count before any observed sign-in: 1
3First signed-out observation must preserve existing T3 Connect registrations
41 !== 0

This confirms the initial-signed-out cleanup behavior in the installed build. It is a lifecycle-level reproduction, not an end-to-end reproduction of offline desktop startup or real catalog deletion.

Source connection and limits

The same behavior is present in the inspected upstream source:

  • cloudAccountService.ts: an initial signed-out observation plans a SignOut step with previousAccountId: null and isAccountTransition: false. The service still enqueues handlers.cleanUp; the transition flag only guards onSignOutTransition.
  • managedAuth.tsx: the desktop/web cleanup handler calls environmentCatalog.removeRelayEnvironments and resets the relay token cache. Inspection of the installed registry code also showed that removing an environment's last route removes its registration.

The update restart plausibly exposed this existing startup behavior, leaving both machines discoverable in the account but no longer saved in the desktop client. However, the incident logs do not record the relevant Clerk emission or pre/post-write catalog contents. I have not established that the network was offline, reproduced the complete offline launch, or shown that this defect was newly introduced by today's update.

Environment: macOS desktop, arm64, Darwin 27.0.0; local server and triage CLI both 0.1.6-nightly.20261031.3973.

Investigation and comment prepared with Codex, model gpt-6.1-sol, on the affected machine.