Skip to content

Desktop shows a fatal "HTTP 500" screen when the backend is busy for more than about 10 s after startup, because the bearer bootstrap budget allows only one attempt #23378

Open

Description

@realhasanshoaib

What happened

On a launch where the backend had just become ready, the desktop window went straight to "Something went wrong. Primary environment request failed during fetch-session-state (HTTP 500)." Clicking "Reload app" about a minute later loaded the app normally, with nothing else changed.

Diagnosis

The desktop's bearer bootstrap gives up before one slow attempt can be retried. DesktopLocalEnvironmentAuth.getBearerToken (apps/desktop/src/backend/DesktopLocalEnvironmentAuth.ts:99-117) retries transient errors every 500 ms, but wraps the whole retry loop in Effect.timeout(BOOTSTRAP_TRANSIENT_RETRY_TIMEOUT), which is 15 s (line 19). Each /oauth/token attempt has its own 10 s timeout (DEFAULT_REMOTE_REQUEST_TIMEOUT_MS, packages/client-runtime/src/authorization/remote.ts:24). So when the backend is briefly unresponsive, the budget covers one full attempt plus half of a second. The trace shows exactly that, twice: a 10.0 s RemoteEnvironmentAuthTimeoutError, then a retry interrupted at 4.5 s.

The web side does not retry either. readDesktopPrimaryBearerToken (apps/web/src/environments/primary/desktopAuth.ts:12-15) clears its cached promise and rethrows, and the route's beforeLoad turns that into the full-screen error.

The error screen also reports a status the server never sent. PrimaryEnvironmentRequestError.fromCause (apps/web/src/environments/primary/auth.ts:54) uses readHttpApiStatus(cause) ?? 500, so the IPC timeout is shown as "HTTP 500".

Why the backend was unresponsive: right after startup, spans across unrelated subsystems stretched to about 35 s (08:51:02 to 08:51:37), and then to about 28 s (08:51:38 to 08:52:06). event-loop-stalls.ndjson has one sample in this period, at 08:52:07, with a 27 s max delay at 100% use. The second stall lines up with ProjectionStore.readShellSnapshotRows (apps/server/src/orchestration-v2/ProjectionStore.ts:6289), a json_extract query over every thread's payload_json that ran 27 to 28 s, and 15.6 s again at 08:52:25. Unrelated spans (git status, GitHub GraphQL, simple ProjectService.getShell selects) stretched to the same length. I could not identify the operation behind the first stall. The state database is 17 GB, so slow queries are expected here. The bug is that a backend that is slow for 30 s turns into a fatal screen.

Of the 32 commits on main after this build (b5a226e..3b95e78), one touches these files, 6f75bcb (ChatGPT Business usage limits), and it does not change this behavior.

Steps to reproduce

Not reproduced on demand. Any way of making /oauth/token take longer than about 10 s during the desktop's first load should show it, for example a large state database (17 GB here) where readShellSnapshotRows takes longer than 10 s, or pausing the backend process for 20 s right after it reports ready.

Version

0.1.2-nightly.20261021.3499 (desktop app and its bundled backend)

Environment

macOS 26.6.2, MacBook Air M4 (16 GB), desktop app, Local environment on, no background service installed

Evidence

desktop.trace.ndjson, local time UTC+4
08:51:03  clientRuntime.authorization.bootstrapRemoteBearerSession  10.0 s  Failure  RemoteEnvironmentAuthTimeoutError: .../oauth/token timed out after 10000ms
08:51:14  clientRuntime.authorization.bootstrapRemoteBearerSession   4.5 s  Interrupted
08:51:03  desktop.localEnvironmentAuth.getBearerToken               15.0 s  Failure  DesktopLocalEnvironmentAuthSessionBootstrapError
08:51:19  (second load) same pattern: 10.0 s timeout, retry interrupted at 4.5 s, getBearerToken fails at 15.0 s

server.trace.ndjson, same run
08:50:52  server.startup                                  9.75 s  (ready at 08:51:02)
08:51:37  sqlite <- ProjectionStore.readShellSnapshotRows 28.6 s
08:51:38  sqlite <- ProjectionStore.readShellSnapshotRows 27.4 s
08:51:38  sqlite <- ProjectService.getShell (x20)         27.8-28.4 s
08:52:25  sqlite <- ProjectionStore.readShellSnapshotRows 15.6 s

event-loop-stalls.ndjson
04:52:07Z  delayMaxMs 27001  utilization 1

Same endpoints one minute later: GET /api/auth/session 200 in 1.5 ms, POST /oauth/token 415 in 1.5 ms (dummy body).

Related issues

#12918 (closed, with #19215 as its duplicate) is the same error chain caused by a transient /oauth/token failure. Its fix, #12919, added the retry described above, but the 15 s overall budget is shorter than what one 10 s attempt plus a retry needs, so a slow backend still reaches the error screen. #23372 is the same install's previous launch, where startup recovery held a write transaction for 11 minutes. That is a different stall: there, readiness never passed.

Fix applied or workaround

Clicked "Reload app" once the backend had settled, about a minute later.

Filed by

claude (claude-opus-5-5) via Claude Code, following the t3 triage playbook

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions