{"record":{"id":"4cabc83ef418c583","repo":"unslothai/unsloth","slug":"chatgpt-authorization-is-no-longer-valid-please-r","errorCode":null,"errorMessage":"ChatGPT authorization is no longer valid. Please reconnect.","messagePattern":"ChatGPT authorization is no longer valid\\. Please reconnect\\.","errorType":"exception","errorClass":"CodexReauthorizationRequired","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/openai_codex_auth.py","lineNumber":278,"sourceCode":"        async with httpx.AsyncClient(\n            timeout = 30.0, follow_redirects = False, trust_env = False\n        ) as client:\n            response = await client.post(OPENAI_CODEX_TOKEN_URL, data = data)\n    except httpx.HTTPError as exc:\n        raise CodexAuthError(\"Could not reach ChatGPT authentication.\") from exc\n    if response.status_code >= 400:\n        error_code = \"\"\n        try:\n            error = response.json().get(\"error\")\n            error_code = error.get(\"code\", \"\") if isinstance(error, dict) else str(error or \"\")\n        except Exception:\n            pass\n        if data.get(\"grant_type\") == \"refresh_token\" and error_code in {\n            \"invalid_grant\",\n            \"invalid_refresh_token\",\n            \"refresh_token_expired\",\n        }:\n            raise CodexReauthorizationRequired(\n                \"ChatGPT authorization is no longer valid. Please reconnect.\"\n            )\n        raise CodexAuthError(\"ChatGPT authorization failed. Please reconnect.\")\n    try:\n        return response.json()\n    except Exception as exc:\n        raise CodexAuthError(\"ChatGPT returned an invalid authorization response.\") from exc\n\n\nasync def _exchange_code(\n    flow: OAuthFlow,\n    code: str,\n    *,\n    verifier: str | None = None,\n    redirect_uri: str | None = None,\n) -> None:\n    if flow.consumed:\n        raise CodexAuthError(\"Authorization callback was already used.\")","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/openai_codex_auth.py#L260-L296","documentation":"Raised as CodexReauthorizationRequired (a subclass of CodexAuthError) when a refresh_token grant to OpenAI's OAuth token endpoint returns HTTP >= 400 with an error code of invalid_grant, invalid_refresh_token, or refresh_token_expired. It means the stored refresh token can no longer mint new access tokens, so the ChatGPT connection must be re-established by the user. Callers (e.g. openai_codex_client.py) catch CodexReauthorizationRequired specifically and mark the provider bundle with reauthorization_required=True so subsequent calls fail fast with the same message.","triggerScenarios":"A call to resolve_access() where the cached access token has expired (bundle['expires_at'] <= time.time() + _REFRESH_SKEW_SECONDS), causing _token_request with grant_type='refresh_token' to receive a 400 response whose JSON error code is 'invalid_grant', 'invalid_refresh_token', or 'refresh_token_expired'. Also produced on force_refresh=True when the saved refresh token was revoked or expired server-side.","commonSituations":"The user revoked the app in their OpenAI/ChatGPT account settings; the refresh token exceeded OpenAI's rotation window; the installation DB was restored from another machine with stale credentials; the account password changed or the session was invalidated; multiple Studio workers raced a refresh and one consumed the rotated token.","solutions":["Catch CodexReauthorizationRequired in the caller and surface a 'reconnect ChatGPT' action to the user instead of retrying — the token is dead.","Delete or disconnect the stored OAuth bundle for the provider_id (the disconnect/delete path clears the bundle) and start a new browser or device flow.","If it recurs immediately after reconnect, check that multiple Studio workers share the installation DB and are not racing token refresh (the provider_oauth_write_guard exists for this).","Verify the system clock is correct; large skew can cause the client to refresh too late against an already-rotated token."],"exampleFix":"// before\ntry:\n    token, account = await resolve_access(provider_id)\nexcept CodexAuthError as exc:\n    log.warning(\"auth failed, retrying\")\n    raise\n\n// after\ntry:\n    token, account = await resolve_access(provider_id)\nexcept CodexReauthorizationRequired:\n    # refresh token revoked/expired - user must reconnect, do not retry\n    await mark_reauthorization_required(provider_id)\n    raise","handlingStrategy":"try-catch","validationCode":"from studio.backend.core.inference import openai_codex_auth as codex_auth\n\nstatus = codex_auth.get_oauth_status(provider_id)\n# status == 'reauthorization_required' predicts this error before any call\nif status == \"reauthorization_required\":\n    prompt_reconnect()","typeGuard":"def is_reauthorization_required(exc: BaseException) -> bool:\n    \"\"\"True when the refresh token is dead and the user must reconnect.\"\"\"\n    return isinstance(exc, codex_auth.CodexReauthorizationRequired)","tryCatchPattern":"try:\n    token, account = await resolve_access(provider_id)\nexcept CodexReauthorizationRequired:\n    # terminal: surface reconnect UX, never retry\n    await show_reconnect_prompt(provider_id)\nexcept CodexAuthError as exc:\n    # other auth failures: log and handle separately\n    log.warning(\"codex auth failed: %s\", exc)","preventionTips":["Check get_oauth_status(provider_id) == 'connected' before issuing inference calls.","Catch CodexReauthorizationRequired separately from CodexAuthError — it subclasses it.","Never auto-retry invalid_grant refreshes; the token is revoked server-side.","Complete reconnect promptly after the error to clear the sticky reauthorization_required flag."],"tags":["oauth","authentication","refresh-token","chatgpt","codex"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}