{"record":{"id":"9432d6212fc19783","repo":"unslothai/unsloth","slug":"the-chatgpt-account-identifier-was-missing","errorCode":null,"errorMessage":"The ChatGPT account identifier was missing.","messagePattern":"The ChatGPT account identifier was missing\\.","errorType":"exception","errorClass":"CodexAuthError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/openai_codex_auth.py","lineNumber":203,"sourceCode":"    challenge = _b64url(hashlib.sha256(verifier.encode(\"ascii\")).digest())\n    return verifier, challenge\n\n\ndef extract_chatgpt_account_id(access_token: str) -> str:\n    \"\"\"Decode only the bounded JWT payload needed as an upstream routing hint.\"\"\"\n    parts = access_token.split(\".\")\n    if len(parts) < 2 or len(parts[1]) > 16_384:\n        raise CodexAuthError(\"ChatGPT returned an invalid access token.\")\n    try:\n        raw = base64.urlsafe_b64decode(parts[1] + \"=\" * (-len(parts[1]) % 4))\n        payload = json.loads(raw)\n    except Exception as exc:\n        raise CodexAuthError(\"ChatGPT returned an invalid access token.\") from exc\n    account_id = payload.get(\"https://api.openai.com/auth\", {}).get(\"chatgpt_account_id\")\n    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:\n        account_id = payload.get(\"https://api.openai.com/auth.chatgpt_account_id\")\n    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:\n        raise CodexAuthError(\"The ChatGPT account identifier was missing.\")\n    return account_id\n\n\ndef _validate_token_payload(body: Any, previous_refresh_token: str = \"\") -> dict[str, Any]:\n    if not isinstance(body, dict):\n        raise CodexAuthError(\"ChatGPT returned an invalid token response.\")\n    access_token = body.get(\"access_token\")\n    refresh_token = body.get(\"refresh_token\") or previous_refresh_token\n    expires_in = body.get(\"expires_in\", 3600)\n    if not isinstance(access_token, str) or not access_token:\n        raise CodexAuthError(\"ChatGPT returned an invalid token response.\")\n    if not isinstance(refresh_token, str) or not refresh_token:\n        raise CodexAuthError(\"ChatGPT did not return a refresh token.\")\n    try:\n        expires_in = max(60, min(int(expires_in), 30 * 24 * 3600))\n    except (TypeError, ValueError) as exc:\n        raise CodexAuthError(\"ChatGPT returned an invalid token lifetime.\") from exc\n    return {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/openai_codex_auth.py#L185-L221","documentation":"Final check in extract_chatgpt_account_id: after decoding the JWT payload, the ChatGPT account id claim must exist and be a usable string. It is read from payload['https://api.openai.com/auth']['chatgpt_account_id'], with a legacy flat-key fallback ('https://api.openai.com/auth.chatgpt_account_id'); both must be a non-empty string of at most 512 chars. If neither yields a valid id, the account identifier is deemed missing.","triggerScenarios":"A token from the wrong tenant/product (e.g. a plain OpenAI API token or a platform token without the ChatGPT auth claim), or an upstream claim rename; the claim exists but is empty/null/numeric/over 512 chars in both locations.","commonSituations":"User authorizes with a non-ChatGPT (API-platform) OpenAI account; OpenAI renames or restructures the auth claim; tokens issued for service principals without a chatgpt_account_id.","solutions":["Reconnect via the ChatGPT OAuth flow so the token carries the ChatGPT auth claim — a plain OpenAI API key/token will not have it.","If upstream renamed the claim, update both lookup keys in extract_chatgpt_account_id to the new location.","Log (safely, without the token) which of the two claim paths was absent to distinguish 'wrong token type' from 'claim moved'."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"auth = payload.get('https://api.openai.com/auth', {})\naccount_id = auth.get('chatgpt_account_id') if isinstance(auth, dict) else None\nif not isinstance(account_id, str) or not account_id:\n    raise ValueError('token lacks ChatGPT account claim; needs ChatGPT (not API) OAuth')","typeGuard":"def token_has_chatgpt_claim(payload: dict) -> bool:\n    auth = payload.get('https://api.openai.com/auth')\n    return isinstance(auth, dict) and isinstance(auth.get('chatgpt_account_id'), str) and bool(auth['chatgpt_account_id'])","tryCatchPattern":"try:\n    account_id = extract_chatgpt_account_id(access_token)\nexcept CodexAuthError as e:\n    if 'account identifier was missing' in str(e):\n        show_message('Connect a ChatGPT account (not an OpenAI API key)')\n    else:\n        raise","preventionTips":["Ensure the OAuth flow used is the ChatGPT one; API-platform tokens will never carry the claim.","Keep the legacy flat-key fallback in sync if upstream moves the claim again.","Log which claim path failed (never the token itself) to speed up diagnosing format drift."],"tags":["oauth","jwt","claims","token-validation","codex"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}