Repository navigation
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) #17367
Copy link
Copy link
Open
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.
Thanks for the detailed traces. Triage notes from current
main(393ff4c):What the code does on a missed envelope
- The desktop starts the primary backend with
--bootstrap-fd 3(DesktopBackendConfiguration.ts#L589-L606) and hands the JSON envelope to fd 3 as a child-process input stream (DesktopBackendManager.ts#L449-L507). The envelope carriesmode: "desktop",host,t3HomeanddesktopBootstrapSecret(#L562-L581). readBootstrapEnvelopewaits 1000 ms by default (L86) and wraps the read inEffect.timeoutOption(L145). A timeout, an unavailable fd (L81-L82) or a stream that closes before a line (L136-L138) all resolve toOption.none()with no log or error.resolveServerConfigthen defaultsmodeto"web".desktopBootstrapSecret/desktopBootstrapTokenstay undefined (L361-L362), soPairingGrantStorehas nothing to accept the desktop's credential with, and the auth policy becomesloopback-browserwith one-time-token bootstrap only (EnvironmentAuthPolicy.ts#L23-L37). The bind host falls back to127.0.0.1(server.ts#L252), so the failure mode looks fail-closed rather than more exposed.- Web-mode defaults also kick in:
autoBootstrapProjectFromCwdturns on (config.ts#L368-L376) andnoBrowserturns off (L352-L360). The packaged backend's cwd is the home directory (DesktopEnvironment.ts#L220), so a fallback launch may also create a project rooted at~and may try to open a browser (serverRuntimeStartup.ts#L531-L537, #L596-L603). Thewelcome.autobootstrapspan in your trace fits that path. Worth checking for a stray home-directory project after a failed launch.
Why it might miss the window after an update (not verified)
- The 1 s timer only starts once
readBootstrapEnveloperuns, so a slow module load before that point should not count against it on its own. Something has to stall the read after the timer is armed. - On Windows there is no
/procor/dev/fdpath (bootstrap.ts#L233-L241), so the envelope is read viafs.createReadStreamon the pipe fd (L207-L214). Reads on that path go through the libuv threadpool (see the analysis in #14776 for the telemetry fd). On a cold first launch with Defender scanning freshly installed files, threadpool contention or a long synchronous stall, as you describe, could plausibly push the read past 1 s even with the envelope sitting in the pipe. Neither has been reproduced here. - No test covers the timeout-then-web-mode fallback; bootstrap.test.ts only exercises the success, unavailable-fd and error paths.
Desktop side
invalid_credentialis final:isTransientBearerBootstrapErrorretries only fetch/timeout and 502-504 (from #12919), and the failure surfaces asDesktopLocalEnvironmentAuthSessionBootstrapError(L118-L124) through the bearer-token IPC (window.ts#L175-L183). Nothing on that path restarts the backend.- Readiness only checks that
/.well-known/t3/environmentanswers (DesktopBackendManager.ts#L378-L399, #L616-L633); the descriptor it returns does not include the server mode, so a web-mode backend looks ready. The sticky error screen is #3513.
Possible fix directions (for maintainers to choose)
- Fail closed on the server: when
--bootstrap-fd/T3CODE_BOOTSTRAP_FDis set and no envelope arrives, exit nonzero with a clear error instead of starting in web mode, so the desktop supervisor restarts it. Smallest change; it does turn a slow start into a restart loop if the stall repeats. - Wait longer: raise the timeout for an explicit fd (or wait until a line or EOF), possibly with a log line when the envelope is late. On Windows, reading the pipe through
net.Socketinstead offs.createReadStream, as #14776 does for telemetry, may remove the threadpool dependency. - Detect the mismatch on the desktop: check the auth descriptor (expecting
desktop-managed-local) or treatinvalid_credentialfrom the primary local backend as "respawn once" before surfacing the error.
Options 1 or 2 address the root cause; option 3 is a safety net and could pair with either.
Related
- #16826: same
invalid_credentialsymptom, different cause (WSL service on the same port). Not a duplicate. - #3513: sticky error UI with no recovery.
- #12918 / #12919: transient bearer bootstrap retries, which don't cover a rejected credential.
- #14776 (open): same
fs.createReadStream-on-pipe pattern for the telemetry fd. - I didn't find an open or merged PR that changes the envelope timeout or the silent web-mode fallback.
- The desktop starts the primary backend with
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.
on Oct 9, 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
What happened
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
webmode server with nodesktopBootstrapSecretand nodesktopBootstrapToken, so it rejects the desktop's credential.--bootstrap-fd 3and writes the JSON envelope (mode,desktopBootstrapSecret, etc.) to that fd at spawn (apps/desktop/src/backend/DesktopBackendManager.ts:449-507).readBootstrapEnvelope(apps/server/src/bootstrap.ts:74) with a default 1000 msEffect.timeoutOption(bootstrap.ts:86,:145). A timeout resolves toOption.none(), and startup continues silently.modefalls back to"web"(apps/server/src/cli/config.ts:288-294).desktopBootstrapSecretanddesktopBootstrapTokenare both undefined, soPairingGrantStoreneither accepts rotating desktop tokens nor seeds a desktop grant (apps/server/src/auth/PairingGrantStore.ts:330-350).POST /oauth/tokenwithcurrentDesktopBootstrapToken(secret, now)returnsinvalid_credential.isTransientBearerBootstrapError(apps/desktop/src/backend/DesktopLocalEnvironmentAuth.ts:27) treats that as final, so it surfaces asDesktopLocalEnvironmentAuthSessionBootstrapErrorand the renderer's rootbeforeLoadfails.Why it happens after updates: the first launch of a freshly installed
server.asaris 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 noreadBootstrapEnvelopespan appears in the trace. But the result, a desktop-spawned backend running withserver.mode: "web", is confirmed, and the otherOption.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-fdsilently degrades to web mode instead of waiting longer or failing loudly. Possible directions, for maintainers to decide:--bootstrap-fdis given explicitly, wait much longer for the envelope, or until EOF.desktopmode before treating it as ready.Steps to reproduce
Not deterministic. It depends on how cold the first post-update start is.
server.trace.ndjsonfor that launch showsserver.startup.welcome.autobootstrapwithserver.mode: "web", followed by failingenvironment.auth.tokenspans.It might reproduce more reliably by artificially delaying the server's startup before
readBootstrapEnvelopeby more than 1 s. I didn't verify this.Version
Desktop 0.0.46-nightly.20261008.2833 (tag v0.0.46-nightly.20261008.2833, a6ec88f); 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
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