{"record":{"id":"4debe053960bba9e","repo":"BerriAI/litellm","slug":"polling-failed-exc","errorCode":null,"errorMessage":"Polling failed: {exc}","messagePattern":"Polling failed: (.+?)","errorType":"exception","errorClass":"GetAccessTokenError","httpStatus":null,"severity":"error","filePath":"litellm/llms/chatgpt/authenticator.py","lineNumber":232,"sourceCode":"                    if all(\n                        key in data\n                        for key in (\n                            \"authorization_code\",\n                            \"code_challenge\",\n                            \"code_verifier\",\n                        )\n                    ):\n                        return data\n                if resp.status_code in (403, 404):\n                    time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))\n                    continue\n                resp.raise_for_status()\n            except httpx.HTTPStatusError as exc:\n                status_code = exc.response.status_code if exc.response else None\n                if status_code in (403, 404):\n                    time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))\n                    continue\n                raise GetAccessTokenError(\n                    message=f\"Polling failed: {exc}\",\n                    status_code=exc.response.status_code,\n                )\n            except Exception as exc:\n                raise GetAccessTokenError(\n                    message=f\"Polling failed: {exc}\",\n                    status_code=400,\n                )\n            time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))\n\n        raise GetAccessTokenError(\n            message=\"Timed out waiting for device authorization\",\n            status_code=408,\n        )\n\n    def _exchange_code_for_tokens(self, code_data: dict[str, str]) -> dict[str, str]:\n        try:\n            client: Final = _get_httpx_client()","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/chatgpt/authenticator.py#L214-L250","documentation":"Raised as `GetAccessTokenError` when polling the ChatGPT device-authorization token endpoint returns an HTTP error other than 403/404 (those are treated as \"keep waiting\" and retried). This occurs during the second phase of device login, after the user has been shown a code.","triggerScenarios":"While waiting for the user to approve the device code at OpenAI's verification page, the token poll returns e.g. 400 (`invalid_grant`, expired device code), 401, or 5xx. The user never finishing authorization before the code expires typically produces a terminal 400.","commonSituations":"User starts `litellm` ChatGPT login but does not complete browser approval within the code's validity window; the auth server invalidates the session; too-slow or hung polling behind flaky networks.","solutions":["Restart the login flow and complete the browser approval promptly after the user code is displayed.","Read the embedded HTTP status/message — 400 with `invalid_grant`/expired means you must start a fresh device-code request, not retry the poll.","If it is a 5xx, retry the whole flow after a minute.","Upgrade litellm in case polling semantics changed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    tokens = authenticator.get_access_token()\nexcept GetAccessTokenError as e:\n    if e.status_code == 400:  # expired/invalid device code: restart flow, don't retry poll\n        device = authenticator._request_device_code()\n        tokens = authenticator.get_access_token()\n    else:\n        raise","preventionTips":["Complete browser approval immediately after the user code appears.","Treat 400 during polling as flow-expired: restart from device-code request.","Retry only 5xx statuses; 4xx poll errors are terminal."],"tags":["chatgpt","oauth","device-flow","polling","auth"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}