{"record":{"id":"64b05b6ad1cd086a","repo":"BerriAI/litellm","slug":"refresh-token-failed-exc","errorCode":null,"errorMessage":"Refresh token failed: {exc}","messagePattern":"Refresh token failed: (.+?)","errorType":"exception","errorClass":"RefreshAccessTokenError","httpStatus":null,"severity":"error","filePath":"litellm/llms/chatgpt/authenticator.py","lineNumber":303,"sourceCode":"            \"id_token\": data[\"id_token\"],\n        }\n\n    def _refresh_tokens(self, refresh_token: str) -> dict[str, str]:\n        try:\n            client: Final = _get_httpx_client()\n            resp: Final = client.post(\n                CHATGPT_OAUTH_TOKEN_URL,\n                json={\n                    \"client_id\": CHATGPT_CLIENT_ID,\n                    \"grant_type\": \"refresh_token\",\n                    \"refresh_token\": refresh_token,\n                    \"scope\": \"openid profile email\",\n                },\n            )\n            resp.raise_for_status()\n            data: Final = resp.json()\n        except httpx.HTTPStatusError as exc:\n            raise RefreshAccessTokenError(\n                message=f\"Refresh token failed: {exc}\",\n                status_code=exc.response.status_code,\n            )\n        except Exception as exc:\n            raise RefreshAccessTokenError(\n                message=f\"Refresh token failed: {exc}\",\n                status_code=400,\n            )\n\n        access_token: Final = data.get(\"access_token\")\n        id_token: Final = data.get(\"id_token\")\n        if not access_token or not id_token:\n            raise RefreshAccessTokenError(\n                message=f\"Refresh response missing fields: {data}\",\n                status_code=400,\n            )\n\n        refreshed: Final = {","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/chatgpt/authenticator.py#L285-L321","documentation":"Raised as `RefreshAccessTokenError` when the refresh-token request (`POST` to `CHATGPT_OAUTH_TOKEN_URL` with `grant_type=refresh_token`) returns an HTTP error. This fires on background token refresh inside the ChatGPT provider when the stored refresh token is rejected or the auth server errors.","triggerScenarios":"Making a chatgpt-provider call after the access token expired, where the stored refresh token is invalid, expired, revoked (user logged out elsewhere), or the server returns 5xx. The upstream status becomes the exception's status_code.","commonSituations":"Long-lived deployments whose stored refresh token aged out or was revoked; multiple machines sharing one auth file causing token rotation races; OpenAI auth incidents; outdated litellm sending a refresh payload the server now rejects.","solutions":["Re-run the device login to obtain fresh tokens (`litellm` chatgpt login flow), replacing the stored auth file.","Ensure only one process uses a given auth file to avoid refresh-token rotation races.","Upgrade litellm so the refresh request matches the current API.","If 5xx, retry after a short backoff before forcing re-login."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = litellm.completion(model=\"chatgpt/gpt-4o\", messages=msgs)\nexcept litellm.AuthenticationError as e:\n    if is_refresh_failure(e):  # inspect message for refresh failure\n        run_chatgpt_login_and_retry()  # mint fresh tokens, then retry once\n    else:\n        raise","preventionTips":["Re-login when refresh tokens expire or are revoked; do not loop retries.","One auth file per process to avoid rotation races.","Alert on repeated refresh failures to catch forced logouts early."],"tags":["chatgpt","oauth","refresh-token","auth","token-expiry"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}