Skip to main content
← Back to list
01Issue
BugShippedSwamp CLI
Assigneesstack72

Relationships

#1478 serve oauth: an unrecognized device-token error kills the whole serve process instead of the bootstrap

Opened by keeb · 7/30/2026· Shipped 7/30/2026

Summary

A mid-flow rejection from POST /api/auth/device/token terminates swamp serve outright rather than surfacing as a handled bootstrap failure. Two gaps combine:

  1. KNOWN_POLL_ERRORS (src/serve/oauth_client.ts:69-74) lists only authorization_pending, slow_down, expired_token, and access_denied. Anything else — invalid_grant, invalid_client, server_error — falls through to throw new Error(...) at oauth_client.ts:135-137 instead of a typed DeviceGrantPollError.
  2. The bootstrap retry loop (src/cli/commands/serve.ts:1171-1198) only swallows DeviceGrantPollError, so a plain Error escapes at serve.ts:1196. There is no try/catch around resolveOAuthClientCredentials (serve.ts:1134), so the process exits FTL.

Net effect: any unexpected answer from the token endpoint during first-boot bootstrap takes the whole server down, mid-poll, with no chance to report a usable error or retry.

Why it matters

This is the mechanism that turned swamp-club lab #1476 from "bootstrap failed" into "the server died." The server started answering 400 invalid_grant "Invalid client ID" partway through a conforming poll sequence; because invalid_grant is not a known poll error, the throw escaped and killed swamp serve. In a Kubernetes deployment that reads as a crashloop rather than a configuration problem.

Fixing the server-side root cause (done, swamp-club side) removes this particular trigger. It does not remove the fragility: any future token-endpoint rejection the CLI does not enumerate will do the same thing.

Steps to reproduce

  1. Start swamp serve --auth-mode oauth against a provider with no stored client credentials, so it enters the bootstrap device grant.
  2. While it polls, make the provider answer /api/auth/device/token with any error outside the four known codes (invalid_grant is the natural one — a revoked or unregistered client id will produce it).
  3. swamp serve exits: error: Error: Token request failed: 400 invalid_grant.

Expected: the bootstrap reports a clear failure (and ideally retries or exits with a diagnosable message); the process should not die inside a poll loop.

Proposed fix

Two independent changes, either of which is an improvement:

  • Treat an unrecognized OAuth error as a terminal poll error rather than an unhandled throw — e.g. extend DeviceGrantPollErrorCode with an unknown/invalid_grant variant so the loop can decide, rather than the error type deciding for it.
  • Wrap resolveOAuthClientCredentials at src/cli/commands/serve.ts:1134 in a try/catch that reports the bootstrap failure and exits deliberately, so no device-flow error can take the process down as a side effect.

Origin

Found while fixing swamp-club lab #1476 (device flow rate-limited to a 45-second window by the server-side validateClient counter). Sibling of #1477 (startDeviceGrant discards the OAuth error field).

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 4 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

7/30/2026, 11:06:19 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack727/30/2026, 9:55:54 PM

Sign in to post a ripple.