{"record":{"id":"3e208c79fa8918d6","repo":"can1357/oh-my-pi","slug":"codex-oauth-credential-is-missing-a-chatgpt-accoun","errorCode":null,"errorMessage":"Codex OAuth credential is missing a ChatGPT account id","messagePattern":"Codex OAuth credential is missing a ChatGPT account id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/codex.ts","lineNumber":809,"sourceCode":"\t\t\t},\n\t\t);\n\t} else {\n\t\tconst seed = await findCodexAuth(params.authStorage, params.sessionId, params.signal);\n\t\tif (!seed) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No Codex OAuth credentials found. Login with 'omp /login openai-codex' to enable Codex web search.\",\n\t\t\t);\n\t\t}\n\n\t\tresult = await withOAuthAccess(\n\t\t\tparams.authStorage,\n\t\t\t\"openai-codex\",\n\t\t\taccess => {\n\t\t\t\t// A refreshed/rotated credential can carry a different bearer and\n\t\t\t\t// ChatGPT account id than the seed used to select the first attempt.\n\t\t\t\tconst accountId = access.accountId ?? getCodexAccountId(access.accessToken);\n\t\t\t\tif (!accountId) {\n\t\t\t\t\tthrow new Error(\"Codex OAuth credential is missing a ChatGPT account id\");\n\t\t\t\t}\n\t\t\t\treturn runCodexSearchCandidates({\n\t\t\t\t\tauth: { accessToken: access.accessToken, accountId },\n\t\t\t\t\tparams,\n\t\t\t\t\tquery,\n\t\t\t\t\tmodelCandidates,\n\t\t\t\t\tmodelWasConfigured: configuredModel !== undefined,\n\t\t\t\t\ttransport,\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ sessionId: params.sessionId, signal: params.signal, seed: seed.access },\n\t\t);\n\t}\n\n\tlet sources = result.sources;\n\n\tconst numResults = params.numSearchResults ?? params.limit;\n\tif (numResults && sources.length > numResults) {","sourceCodeStart":791,"sourceCodeEnd":827,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/codex.ts#L791-L827","documentation":"Inside withOAuthAccess, each attempt derives the ChatGPT account id from the access token (or the access object). Codex's backend requires the chatgpt-account-id header; if a refreshed/rotated credential yields no account id (neither access.accountId nor extractable from the bearer token), searchCodex throws a plain Error because the request cannot be authenticated correctly.","triggerScenarios":"The OAuth access token obtained (including after mid-search refresh/rotation) lacks an accountId field AND getCodexAccountId(accessToken) fails to decode an account id from the JWT claims — typically a malformed, non-ChatGPT, or structurally changed token.","commonSituations":"Auth storage holding a hand-copied or truncated access token; token issued to a non-ChatGPT OAuth client; upstream token format change after an OpenAI update; corrupted auth.json.","solutions":["Re-login with `omp /login openai-codex` to obtain a fresh token containing account-id claims.","Delete the stale openai-codex entry in auth storage and authenticate again.","Check for a package update if OpenAI changed the token claim structure (getCodexAccountId parsing).","Ensure no manual edits/injections replaced the stored access token with a non-ChatGPT bearer."],"exampleFix":"// before\n# auth.json contains token copied from another OpenAI client (no chatgpt account claim)\n// after\n$ rm ~/.omp/auth/openai-codex.json && omp /login openai-codex","handlingStrategy":"try-catch","validationCode":"function tokenHasAccountId(token: string): boolean {\n  try {\n    const claims = JSON.parse(atob(token.split(\".\")[1]));\n    return Boolean(claims[\"chatgpt_account_id\"]);\n  } catch { return false; }\n}","typeGuard":"function isMissingAccountIdError(e: unknown): e is Error {\n  return e instanceof Error && e.message === \"Codex OAuth credential is missing a ChatGPT account id\";\n}","tryCatchPattern":"try {\n  return await searchCodex(params);\n} catch (e) {\n  if (isMissingAccountIdError(e)) {\n    await relogin(\"openai-codex\");\n    return searchCodex(params);\n  }\n  throw e;\n}","preventionTips":["Never hand-edit auth storage tokens; always obtain them via `omp /login openai-codex`.","Re-login after any error mentioning rotated/refreshed credentials.","Watch for OpenAI token format changes and update the package promptly."],"tags":["authentication","oauth","jwt","codex","token-refresh"],"backgroundTag":"missing-claim-in-token","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}