coleam00/Archon · error

OAuth state mismatch.

Error message

OAuth state mismatch.

What it means

Thrown by runOpenAiManualLogin when the user pastes an OpenAI OAuth authorization response whose `state` parameter is present but does not match the `state` issued for the in-flight PKCE flow. The state parameter is a CSRF protection binding the pasted callback to this login session; a mismatch means the code belongs to a different/older login attempt.

Source

Thrown at packages/core/src/credentials/oauth-bridge.ts:219

/**
 * The Archon-owned ChatGPT/Codex manual login (#1924): build the authorize
 * URL (PKCE), surface it on the session, wait for the pasted redirect URL /
 * code via the same `codeDeferred` the Pi manual flows use (so poll(code) and
 * abort semantics are identical), then exchange it directly — capturing the
 * `id_token` Pi drops. Runs NO local callback server (the #1963 wedge
 * pattern); the user pastes the final redirect URL or code back instead.
 */
async function runOpenAiManualLogin(session: OAuthSession): Promise<OpenAiOAuthCredentials> {
  const flow = createOpenAiAuthorizeFlow();
  session.url = flow.url;
  if (session.mode === 'pending') session.mode = 'manual';
  session.firstSignal.resolve(true);
  // Rejected by abortSession on cancel/supersede/expiry — same as Pi flows.
  const input = await session.codeDeferred.promise;
  const parsed = parseOpenAiAuthorizationInput(input);
  if (parsed.state && parsed.state !== flow.state) {
    throw new Error('OAuth state mismatch.');
  }
  if (!parsed.code) {
    throw new Error('Missing authorization code.');
  }
  // Returns its true type — the loginPromise join is typed as delivery.ts's
  // loose `OAuthCredentials`, which this satisfies structurally (no cast).
  return exchangeOpenAiAuthorizationCode(parsed.code, flow.verifier, session.abort.signal);
}

/**
 * Begin a subscription login for a vendor (anthropic/openai/github-copilot;
 * legacy claude/codex/copilot ids accepted). Kicks off the held login —
 * Pi's `login()` for anthropic/github-copilot, the Archon-owned PKCE flow for
 * openai — and returns once the first signal has populated the URL (manual)
 * or user-code (device), or a short timeout elapses.
 */
export async function startOAuth(userId: string, providerId: string): Promise<StartOAuthResult> {
  // Expired sessions may also hold a callback server — include them in the

View on GitHub (pinned to 0773b97458)

Solutions

  1. Complete the login again and paste the authorization response from that exact attempt (same state value).
  2. Cancel any other concurrent OpenAI logins so only one flow is live, then retry.
  3. Copy the full redirect URL from the browser tab the current login opened — not an older one.
  4. If the state keeps mismatching, restart the login to mint a fresh flow and state.

Example fix

// before: pasting stale URL from a cancelled attempt
https://auth.openai.com/oauth/callback?state=OLD_STATE&code=...
// after: fresh response from the current login attempt
https://auth.openai.com/oauth/callback?state=CURRENT_STATE&code=...
Defensive patterns

Strategy: retry

Validate before calling

import { parseOpenAiAuthorizationInput } from './openai-oauth';
function inputMatchesFlow(input: string, flow: { state: string }): boolean {
  const parsed = parseOpenAiAuthorizationInput(input);
  return !parsed.state || parsed.state === flow.state;
}

Try / catch

try {
  const creds = await loginPromise;
} catch (e) {
  if ((e as Error).message === 'OAuth state mismatch.') {
    // restart the login flow and paste the response from the NEW attempt
  } else throw e;
}

Prevention

When it happens

Trigger: During manual OpenAI subscription login, supplying a code via the deferred prompt (session.codeDeferred) where parseOpenAiAuthorizationInput extracts a state that differs from flow.state — pasting a callback URL from a previous login attempt, a different browser session, or a stale/stopped flow.

Common situations: Re-pasting an old authorization URL after the login was cancelled and restarted; running two logins concurrently and mixing up their callback URLs; copying the redirect from a different Archon instance.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/e783878b747c1c9b. Report an issue: GitHub.