unslothai/unsloth · error · CodexAuthError
ChatGPT did not return a refresh token.
Error message
ChatGPT did not return a refresh token.
What it means
Validation in _validate_token_payload for the refresh token: after falling back (body['refresh_token'] or previous_refresh_token), the result must be a non-empty string. ChatGPT tokens are rotated on every refresh, so the endpoint must hand back a usable refresh token; if it omits one and no previous token was supplied to reuse, the credential cannot be persisted for future refreshes and the flow fails.
Source
Thrown at studio/backend/core/inference/openai_codex_auth.py:216
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),
}
def save_oauth_bundle(provider_id: str, bundle: dict[str, Any]) -> None:
credential_secrets.upsert_secret(
credential_secrets.OPENAI_CODEX_OAUTH_KIND,
provider_id,
json.dumps(bundle, separators = (",", ":")),
)View on GitHub (pinned to 203007d190)
Solutions
- Restart the OAuth authorization flow (full reconnect) to obtain a fresh refresh token instead of refreshing a half-broken credential.
- Check the authorization request included the offline-access scope/parameters ChatGPT OAuth requires for refresh tokens.
- Persist the latest refresh_token after every exchange so the previous_refresh_token fallback is available on rotation hiccups.
Defensive patterns
Strategy: fallback
Validate before calling
refresh_token = body.get('refresh_token') or previous_refresh_token
if not isinstance(refresh_token, str) or not refresh_token:
raise ValueError('no refresh token available; full re-authorization required') Try / catch
try:
bundle = _validate_token_payload(body, previous_refresh_token=stored_refresh)
except CodexAuthError as e:
if 'refresh token' in str(e):
bundle = await full_reauthorization(provider_id) # fresh code exchange
else:
raise Prevention
- Always pass the last stored refresh token as previous_refresh_token so rotation hiccups are survivable.
- Request offline access in the authorization call so refresh tokens are issued.
- Persist the new refresh token atomically after every exchange.
When it happens
Trigger: A refresh_token grant response that omits refresh_token while _validate_token_payload was called without previous_refresh_token; or the field present but empty/non-string.
Common situations: Upstream policy change stopping refresh-token rotation; a first-time code-exchange response missing the refresh token (scope/PKCE misconfiguration); mocks that only return access_token.
Related errors
- ChatGPT authorization is no longer valid. Please reconnect.
- ChatGPT credential update is busy. Please retry.
- ChatGPT returned an invalid access token.
- The ChatGPT account identifier was missing.
- ChatGPT returned an invalid token response.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/acb7753540468465.
Report an issue: GitHub.