BerriAI/litellm · error · GigaChatAuthError

Invalid token response: {data}

Error message

Invalid token response: {data}

What it means

Raised inside _parse_token_response when the GigaChat OAuth endpoint returned HTTP 200 but the JSON body contains neither a 'tok' nor an 'access_token' field. litellm accepts both the native Sberbank shape ({tok, exp}) and an OAuth-style shape ({access_token, expires_at}); if both lookups are falsy it throws GigaChatAuthError(500) with the full parsed body in the message. This indicates an auth-endpoint contract change or an unexpected (possibly proxied/cached) 200 response.

Source

Thrown at litellm/llms/gigachat/authenticator.py:229

            message=f"GigaChat authentication failed: {e.response.text}",
        )
    except httpx.RequestError as e:
        raise GigaChatAuthError(
            status_code=500,
            message=f"GigaChat authentication request failed: {e}",
        )


def _parse_token_response(response: httpx.Response) -> tuple[str, int]:
    """Parse OAuth token response."""
    data: Final = response.json()

    # GigaChat returns either 'tok'/'exp' or 'access_token'/'expires_at'
    access_token: Final = data.get("tok") or data.get("access_token")
    expires_at = data.get("exp") or data.get("expires_at")

    if not access_token:
        raise GigaChatAuthError(
            status_code=500,
            message=f"Invalid token response: {data}",
        )

    # expires_at is in milliseconds
    if isinstance(expires_at, str):
        expires_at = int(expires_at)

    verbose_logger.debug("GigaChat access token obtained successfully")
    return access_token, expires_at

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Inspect the data dict printed in the error message — it shows exactly which fields the endpoint returned instead of tok/access_token.
  2. If using a custom GIGACHAT_API_BASE, verify the endpoint returns the Sberbank OAuth shape ({"tok": "...", "exp": <ms>}) or {"access_token": ..., "expires_at": ...}.
  3. Test the raw exchange directly: curl -X POST <auth_url> -H "Authorization: Basic <base64 key>" -d 'scope=GIGACHAT_API_PERS' and inspect the JSON.
  4. If the upstream format genuinely changed, pin/patch litellm's _parse_token_response or open an issue upstream with the response shape.

Example fix

# before: custom gateway returns {"accessToken": ...} -> litellm raises 'Invalid token response'
os.environ["GIGACHAT_API_BASE"] = "https://my-gateway.example.com"

# after: point at a gateway that passes through the native OAuth shape, or proxy-rewrite the field
# (gateway config: map "accessToken" -> "tok", "expiresInMs" -> "exp")
os.environ["GIGACHAT_API_BASE"] = "https://my-gateway.example.com"  # now returns {"tok": ..., "exp": ...}
Defensive patterns

Strategy: validation

Validate before calling

import base64, os, httpx

key = os.environ["GIGACHAT_API_KEY"]
scope = os.getenv("GIGACHAT_API_SCOPE", "GIGACHAT_API_PERS")
auth_url = os.getenv("GIGACHAT_API_BASE", "https://ngw.devices.sberbank.ru:9443") + "/api/v1/oauth"

resp = httpx.post(auth_url,
    headers={"Authorization": f"Basic {key}", "Content-Type": "application/x-www-form-urlencoded"},
    data={"scope": scope}, timeout=30, verify=False)
data = resp.json()
assert data.get("tok") or data.get("access_token"), f"Unexpected token response shape: {list(data)}"

Try / catch

from litellm.exceptions import AuthenticationError

try:
    litellm.completion(model="gigachat/GigaChat-Pro", messages=msgs)
except AuthenticationError as e:
    if "Invalid token response" in str(e):
        # body is embedded; use it to diagnose gateway/contract drift
        raise RuntimeError(f"GigaChat auth endpoint returned unexpected JSON; inspect body in message: {e}") from e
    raise

Prevention

When it happens

Trigger: The POST to the auth URL succeeds with 2xx, but the body is e.g. an HTML login page served by a captive portal/proxy that httpx .json() happens to parse (or a JSON error envelope like {"status": 401, "message": ...} returned with 200), or GigaChat changed its token field names in an API revision. Also triggered when a custom GIGACHAT_API_BASE points at a gateway whose token response format differs from Sberbank's.

Common situations: Self-hosted API gateways or mock servers in front of GigaChat that return a different token schema; GigaChat API version drift between when the key was issued and now; a WAF rewriting the auth response; a custom api_base copied from a different integration tutorial.

Understand the failure class

Related errors


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