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

opened15d agobyJjosephv123

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.