BerriAI/litellm · error · GetAccessTokenError
Token exchange response missing fields
Error message
Token exchange response missing fields: {data} What it means
GetAccessTokenError (status 400) raised when the ChatGPT token endpoint returned 200 and parseable JSON, but the body is missing any of access_token, refresh_token, or id_token. litellm requires all three before building the auth record, so a response without the full token set is treated as a failed exchange. The raw payload is echoed in the message.
Solutions
- Upgrade litellm to the latest version so token parsing matches the current response schema
- Bypass any proxy/mock in front of auth.openai.com and retry
- Inspect the {data} payload printed in the message to see exactly which token is absent
- If it persists, restart the device login to get a fresh, well-formed exchange
Defensive patterns
Strategy: try-catch
Try / catch
from litellm.llms.chatgpt.authenticator import GetAccessTokenError
try:
tokens = authenticator.login()
except GetAccessTokenError as e:
if "missing fields" in str(e):
print("Token response schema changed; upgrade litellm (pip install -U litellm).")
raise Prevention
- Upgrade litellm promptly when OpenAI auth endpoints change behavior
- Do not intercept auth.openai.com with test doubles in production paths
- Log (redacted) auth failures so schema regressions are visible early
When it happens
Trigger: The token endpoint responding 200 with a partial payload — e.g. only an error sub-object or an id_token-less body; a proxy/mock rewriting the response; an OpenAI schema change the installed litellm predates.
Common situations: Stale litellm versions after OpenAI alters the OAuth token response; test harnesses mocking the token endpoint incompletely; middleware injecting modified responses on auth domains.
Related errors
- Device code response missing fields
- Token exchange failed
- Failed to request device code
- Polling failed
- Timed out waiting for device authorization
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/64194c308214574d.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/chatgpt/authenticator.py:278
CHATGPT_OAUTH_TOKEN_URL,
headers={"Content-Type": "application/x-www-form-urlencoded"},
content=body,
)
resp.raise_for_status()
data: Final = resp.json()
except httpx.HTTPStatusError as exc:
raise GetAccessTokenError(
message=f"Token exchange failed: {exc}",
status_code=exc.response.status_code,
)
except Exception as exc:
raise GetAccessTokenError(
message=f"Token exchange failed: {exc}",
status_code=400,
)
if not all(key in data for key in ("access_token", "refresh_token", "id_token")):
raise GetAccessTokenError(
message=f"Token exchange response missing fields: {data}",
status_code=400,
)
return {
"access_token": data["access_token"],
"refresh_token": data["refresh_token"],
"id_token": data["id_token"],
}
def _refresh_tokens(self, refresh_token: str) -> dict[str, str]:
try:
client: Final = _get_httpx_client()
resp: Final = client.post(
CHATGPT_OAUTH_TOKEN_URL,
json={
"client_id": CHATGPT_CLIENT_ID,
"grant_type": "refresh_token",
"refresh_token": refresh_token,View on GitHub (pinned to 77b7c6c40c)