Skip to content

[Bug]: a time-valid stored Codex pool token is quarantined on the first Responses 401 #2887

Description

@luvs01

Client or integration

Codex App

Area

Authentication and account pool

Summary

An ordinary stored Codex pool credential can be quarantined on the first pre-stream Responses 401, even when its access token is still time-valid and a refresh token is available.

This is distinct from native __main__ handling in #2221/#2848 and WHAM usage refresh handling in #1932/#2021. Ordinary stored accounts resolve as authCtx.kind === "pool"; their time-valid access token bypasses refresh, while the bounded 401 refresh-and-replay path currently only handles main-pool. The first upstream 401 therefore reaches the terminal credential-failure path, marks the stored account needsReauth, and clears its affinity without trying one same-account refresh.

Expected behavior: for an ordinary stored pool account, the first pre-stream/header 401 should perform one generation-fenced, single-flight forced refresh and rebuild the same account's request exactly once. Only a terminal refresh failure or a second 401 from the matching credential generation should quarantine that account.

Reproduction

  1. Store an ordinary Codex pool account with an access token, refresh token, account ID, needsReauth: false, and expiresAt > Date.now() + 60_000.
  2. Select or fix that account for a /v1/responses request.
  3. In a deterministic test harness, return 401 for the old bearer token, return fresh rotated tokens from the OAuth token endpoint, and return 200 for the replay using the new bearer token.
  4. Observe the current behavior: the old bearer is sent once, the refresh endpoint is not called, the client receives 401, and the account is marked needsReauth with its affinity cleared.

The same gap applies to /v1/responses/compact.

Suggested acceptance boundaries:

  • Refresh and replay at most once, on the same ordinary pool account, for a first pre-stream/header 401.
  • Fence refresh, persistence, and final quarantine by the rejected account ID and credential generation so a stale 401 cannot overwrite or quarantine a concurrently replaced credential.
  • Coalesce concurrent same-generation refreshes into one token-endpoint call and one generation increment.
  • Preserve fixed-account, pin, and affinity semantics; do not select a different account for the first replay.
  • Do not quarantine on cancellation, lock contention, network failure, or another transient refresh error.
  • Do not replay a mid-stream failure, exceed the request's total recovery budget, or expose access/refresh tokens in logs or errors.

Version

2.35.0; also present on dev at 8621acb8756c1656676452f4a6c853d2d720c08f

Operating system

Windows 11 Pro 10.0.26200

Provider and model

OpenAI Codex account pool / native GPT-5.6 family

Logs or error output

Synthetic harness result:
upstream sends: 1 (old bearer)
OAuth refresh calls: 0
client response: 401
stored account: needsReauth=true; affinity removed

Screenshots and supporting files

Not required; the reproduction is deterministic and contains no account data.

Redacted configuration

{
  "codexAuth": {
    "mode": "pool",
    "accountSelectionStrategy": "fill-first"
  }
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

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

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions