# First launch after a desktop update can start the backend in web mode without the bootstrap secret, so the desktop's own login is rejected \(invalid_credential\) · Issue \#17367 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/issues/17367)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: backlog

Priority: 0

## Description

[Discussion and activity](https://git.cafe/pingdotgg/t3code/issues/17367)

---

### What happened

> I'm on T3 Code nightly on Windows. Always when I update the app and restart it, this error appears:
>
> ```
> Something went wrong.
> Primary environment request failed during fetch-session-state (HTTP 500).
> ```

Fully quitting and reopening the app makes it work again. "Try again" and "Reload app" don't help (see #3513).

### Diagnosis

On the first launch after an update, the desktop's own backend can start **without its desktop bootstrap envelope**. It then runs as a plain `web` mode server with no `desktopBootstrapSecret` and no `desktopBootstrapToken`, so it rejects the desktop's credential.

1. The desktop spawns the backend with `--bootstrap-fd 3` and writes the JSON envelope (mode, `desktopBootstrapSecret`, etc.) to that fd at spawn (`apps/desktop/src/backend/DesktopBackendManager.ts:449-507`).
2. The server reads it in `readBootstrapEnvelope` (`apps/server/src/bootstrap.ts:74`) with a default **1000 ms** `Effect.timeoutOption` (`bootstrap.ts:86`, `:145`). A timeout resolves to `Option.none()`, and startup continues silently.
3. With no envelope, `mode` falls back to `"web"` (`apps/server/src/cli/config.ts:288-294`). `desktopBootstrapSecret` and `desktopBootstrapToken` are both undefined, so `PairingGrantStore` neither accepts rotating desktop tokens nor seeds a desktop grant (`apps/server/src/auth/PairingGrantStore.ts:330-350`).
4. The desktop's `POST /oauth/token` with `currentDesktopBootstrapToken(secret, now)` returns `invalid_credential`. `isTransientBearerBootstrapError` (`apps/desktop/src/backend/DesktopLocalEnvironmentAuth.ts:27`) treats that as final, so it surfaces as `DesktopLocalEnvironmentAuthSessionBootstrapError` and the renderer's root `beforeLoad` fails.

Why it happens after updates: the first launch of a freshly installed `server.asar` is a cold start (no compile cache, and likely Defender scanning new files). On this machine that backend took about 9 s from spawn to initialized services (spawn 23:39:54.8Z, services up about 23:40:03–05Z). My **hypothesis** is that a long synchronous stretch blocks the event loop past 1 s around the envelope read. When the loop wakes up, the expired timer is handled before the pending pipe read (Node runs timers before poll I/O), so the envelope is dropped even though it is already in the pipe. I couldn't confirm the timeout directly because no `readBootstrapEnvelope` span appears in the trace. But the result, a desktop-spawned backend running with `server.mode: "web"`, is confirmed, and the other `Option.none()` paths (fd not stat-able, stream closed before a line) seem unlikely for a pipe the desktop has just written to.

The core problem is that a backend launched with an explicit `--bootstrap-fd` silently degrades to web mode instead of waiting longer or failing loudly. Possible directions, for maintainers to decide:
- When `--bootstrap-fd` is given explicitly, wait much longer for the envelope, or until EOF.
- Exit with a clear error instead of starting in web mode, so the desktop's supervisor restarts it.
- Have the desktop verify that the backend reports `desktop` mode before treating it as ready.

### Steps to reproduce

Not deterministic. It depends on how cold the first post-update start is.

1. Install T3 Code (Nightly) desktop on Windows, using the Windows backend (not WSL-only).
2. Let it download a nightly update, then click install/restart.
3. On the first launch of the new version, the app often shows "Primary environment request failed during fetch-session-state (HTTP 500)". In this user's logs it happened on 2 of the last 3 updates.
4. `server.trace.ndjson` for that launch shows `server.startup.welcome.autobootstrap` with `server.mode: "web"`, followed by failing `environment.auth.token` spans.
5. Fully quit and relaunch: the backend starts in desktop mode and login succeeds.

It might reproduce more reliably by artificially delaying the server's startup before `readBootstrapEnvelope` by more than 1 s. I didn't verify this.

### Version

Desktop 0.0.46-nightly.20261008.2833 (tag v0.0.46-nightly.20261008.2833, a6ec88f7a7); bootstrap.ts unchanged on main as of 2026-10-08

### Environment

Windows 11 Home 10.0.26200 x64, desktop app with local Windows backend on port 3773 (no WSL backend, no background service)

### Evidence

```shell
# Update installs and app startups (desktop.trace.ndjson)
2026-10-07T20:20:01Z desktop.updates.install
2026-10-07T20:20:40Z desktop.startup          -> FAILED (backend in web mode)
2026-10-07T20:20:57Z desktop.startup          -> OK (manual relaunch)
2026-10-08T13:22:44Z desktop.updates.install
2026-10-08T13:23:23Z desktop.startup          -> OK
2026-10-08T23:39:15Z desktop.updates.install
2026-10-08T23:39:53Z desktop.startup          -> FAILED (backend in web mode)

# Failing launch: desktop side
23:39:54.760Z desktop.backendInstance.start {"id":"primary"}
23:39:54.821Z http.client GET /.well-known/t3/environment  Failure   (backend not up yet)
23:40:06.857Z http.client GET /.well-known/t3/environment  Success
23:40:07.519Z http.client POST http://127.0.0.1:3773/oauth/token
23:40:07.514Z desktop.localEnvironmentAuth.getBearerToken  Failure
  DesktopLocalEnvironmentAuthSessionBootstrapError: Failed to create the local desktop bearer session.
    [cause]: EnvironmentAuthInvalidError: The environment rejected this client's credentials (invalid_credential).

# Failing launch: server side (same traceId 74529fb7…, so the same backend handled the request)
23:40:05.694Z server.startup.welcome.autobootstrap {"server.mode":"web","server.port":3773,"server.host":"default"}
23:40:07.523Z environment.auth.token Failure  EnvironmentAuthInvalidError (invalid_credential)  url.path=/oauth/token
23:40:07.633Z environment.auth.token Failure  EnvironmentAuthInvalidError (invalid_credential)

# Oct 7 failure shows the same pattern
2026-10-07T20:20:50.958Z server.startup.welcome.autobootstrap {"server.mode":"web",...}
2026-10-07T20:20:52.867Z environment.auth.token Failure

# Only one listener on the port; it is the desktop-spawned backend
LocalAddress LocalPort OwningProcess
127.0.0.1    3773      22848   # T3 Code (Nightly).exe ... server.asar\apps\server\dist\bin.mjs --bootstrap-fd 3 (child of the desktop main process)
```

### Related issues

#16826: same invalid_credential symptom, but there a WSL service takes the port via wslrelay.exe; here only the desktop's own backend listens and it reports server.mode web. #3513: why the error screen needs a full quit. #12918/#12919: retries only cover transient 502-504, invalid_credential is final.

### Fix applied or workaround

Nothing was changed on the machine. Workaround: when the error appears, fully quit T3 Code (including the tray icon) and reopen it so the backend is respawned.

### Filed by

Claude Code (Claude Opus 5.5, claude-opus-5-5) via t3 triage
