unslothai/unsloth · error · CodexAuthError

ChatGPT returned an invalid token response.

Error message

ChatGPT returned an invalid token response.

What it means

First validation in _validate_token_payload: the body returned by the ChatGPT token endpoint must be a dict (a JSON object). If the response parsed to a list, string, number, or None (e.g. the endpoint returned a JSON array or a plain error string with HTTP 200-ish handling), the extractor cannot read access_token/refresh_token fields and raises this CodexAuthError.

Source

Thrown at studio/backend/core/inference/openai_codex_auth.py:209

    parts = access_token.split(".")
    if len(parts) < 2 or len(parts[1]) > 16_384:
        raise CodexAuthError("ChatGPT returned an invalid access token.")
    try:
        raw = base64.urlsafe_b64decode(parts[1] + "=" * (-len(parts[1]) % 4))
        payload = json.loads(raw)
    except Exception as exc:
        raise CodexAuthError("ChatGPT returned an invalid access token.") from exc
    account_id = payload.get("https://api.openai.com/auth", {}).get("chatgpt_account_id")
    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:
        account_id = payload.get("https://api.openai.com/auth.chatgpt_account_id")
    if not isinstance(account_id, str) or not account_id or len(account_id) > 512:
        raise CodexAuthError("The ChatGPT account identifier was missing.")
    return account_id


def _validate_token_payload(body: Any, previous_refresh_token: str = "") -> dict[str, Any]:
    if not isinstance(body, dict):
        raise CodexAuthError("ChatGPT returned an invalid token response.")
    access_token = body.get("access_token")
    refresh_token = body.get("refresh_token") or previous_refresh_token
    expires_in = body.get("expires_in", 3600)
    if not isinstance(access_token, str) or not access_token:
        raise CodexAuthError("ChatGPT returned an invalid token response.")
    if not isinstance(refresh_token, str) or not refresh_token:
        raise CodexAuthError("ChatGPT did not return a refresh token.")
    try:
        expires_in = max(60, min(int(expires_in), 30 * 24 * 3600))
    except (TypeError, ValueError) as exc:
        raise CodexAuthError("ChatGPT returned an invalid token lifetime.") from exc
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "expires_at": int(time.time()) + expires_in,
        "account_id": extract_chatgpt_account_id(access_token),
    }

View on GitHub (pinned to 203007d190)

Solutions

  1. Retry the OAuth/token request — a transient intermediary (proxy, captive portal) producing malformed bodies often clears.
  2. If reproducible, capture the raw response body/status to confirm whether the endpoint or an intermediary is misbehaving, and report/adjust.
  3. For tests/mocks, make the fake token response a JSON object with access_token/refresh_token/expires_in.
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(body, dict):
    raise ValueError(f'expected JSON object from token endpoint, got {type(body).__name__}')

Type guard

def is_token_body(body: object) -> TypeGuard[dict]:
    return isinstance(body, dict)

Try / catch

try:
    bundle = _validate_token_payload(body)
except CodexAuthError as e:
    if 'invalid token response' in str(e):
        log_raw_response_shape(body)  # never log token values
        retry_or_reauth()
    else:
        raise

Prevention

When it happens

Trigger: The token endpoint (OPENAI_CODEX_TOKEN_URL) responding with a non-object JSON body — array, scalar, or null — which httpx .json() happily parses but isinstance(body, dict) rejects.

Common situations: A proxy or captive portal intercepting the auth request and returning odd JSON; upstream API change; an error envelope that is itself a list; testing with mocked responses shaped incorrectly.

Understand the failure class

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/30b188e6f07133f2. Report an issue: GitHub.