BerriAI/litellm · error · GetAccessTokenError

Polling failed: {exc}

Error message

Polling failed: {exc}

What it means

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.

Source

Thrown at litellm/llms/chatgpt/authenticator.py:232

                    if all(
                        key in data
                        for key in (
                            "authorization_code",
                            "code_challenge",
                            "code_verifier",
                        )
                    ):
                        return data
                if resp.status_code in (403, 404):
                    time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))
                    continue
                resp.raise_for_status()
            except httpx.HTTPStatusError as exc:
                status_code = exc.response.status_code if exc.response else None
                if status_code in (403, 404):
                    time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))
                    continue
                raise GetAccessTokenError(
                    message=f"Polling failed: {exc}",
                    status_code=exc.response.status_code,
                )
            except Exception as exc:
                raise GetAccessTokenError(
                    message=f"Polling failed: {exc}",
                    status_code=400,
                )
            time.sleep(max(interval, DEVICE_CODE_POLL_SLEEP_SECONDS))

        raise GetAccessTokenError(
            message="Timed out waiting for device authorization",
            status_code=408,
        )

    def _exchange_code_for_tokens(self, code_data: dict[str, str]) -> dict[str, str]:
        try:
            client: Final = _get_httpx_client()

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Restart the login flow and complete the browser approval promptly after the user code is displayed.
  2. Read the embedded HTTP status/message — 400 with `invalid_grant`/expired means you must start a fresh device-code request, not retry the poll.
  3. If it is a 5xx, retry the whole flow after a minute.
  4. Upgrade litellm in case polling semantics changed.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    tokens = authenticator.get_access_token()
except GetAccessTokenError as e:
    if e.status_code == 400:  # expired/invalid device code: restart flow, don't retry poll
        device = authenticator._request_device_code()
        tokens = authenticator.get_access_token()
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/4debe053960bba9e. Report an issue: GitHub.