xtekky/gpt4free · error · RuntimeError
Token exchange failed: {error_text}
Error message
Token exchange failed: {error_text} What it means
The authorization-code-for-token exchange POST to https://oauth2.googleapis.com/token returned a non-ok status. The raw Google error body (JSON with error/error_description such as 'invalid_grant', 'redirect_uri_mismatch', 'invalid_client') is embedded in the message.
Source
Thrown at g4f/Provider/needs_auth/Antigravity.py:648
"client_id": cls.OAUTH_CLIENT_ID,
"client_secret": cls.OAUTH_CLIENT_SECRET,
"code": code,
"grant_type": "authorization_code",
"redirect_uri": ANTIGRAVITY_REDIRECT_URI,
"code_verifier": verifier,
}
async with session.post(
"https://oauth2.googleapis.com/token",
data=token_data,
headers={
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "google-api-nodejs-client/10.3.0",
},
) as resp:
if not resp.ok:
error_text = await resp.text()
raise RuntimeError(f"Token exchange failed: {error_text}")
token_response = await resp.json()
access_token = token_response.get("access_token")
refresh_token = token_response.get("refresh_token")
expires_in = token_response.get("expires_in", 3600)
if not access_token or not refresh_token:
raise RuntimeError("Missing tokens in response")
# Get user info
email = None
async with session.get(
"https://www.googleapis.com/oauth2/v1/userinfo?alt=json",
headers={"Authorization": f"Bearer {access_token}"},
) as resp:
if resp.ok:
user_info = await resp.json()View on GitHub (pinned to 973504e177)
Solutions
- Parse error_text: 'invalid_grant' -> code expired/used; restart the login flow for a fresh code. 'redirect_uri_mismatch' -> ensure the exact ANTIGRAVITY_REDIRECT_URI (localhost callback) is used and not rewritten by a proxy.
- Do not retry the exchange with the same code; authorization codes are single-use.
- Complete the browser consent promptly after generating the auth URL.
- Ensure no browser extension or proxy strips the state/code query parameters from the localhost redirect.
Defensive patterns
Strategy: try-catch
Try / catch
try:
tokens = await Antigravity.exchange_code_for_tokens(code, state)
except RuntimeError as e:
if "Token exchange failed" in str(e):
# do NOT reuse `code`; generate a new authorization URL and retry once
raise Prevention
- Exchange the authorization code immediately after the callback — codes expire in minutes and are single-use
- Never retry an exchange with the same code after any error
- Keep redirect_uri identical between the authorization request and the exchange
When it happens
Trigger: POST with grant_type=authorization_code, code, redirect_uri=ANTIGRAVITY_REDIRECT_URI, code_verifier. Fails with: expired or already-used authorization code (codes are single-use and ~10 min TTL), redirect_uri mismatch against the Google OAuth app config, wrong PKCE verifier, or bad client_id/client_secret.
Common situations: User took too long between opening the auth URL and completing consent; the callback fired twice and the code was consumed; the redirect URI recorded in Google's console differs from ANTIGRAVITY_REDIRECT_URI; retrying the exchange after a network error reused the same code.
Related errors
- Token refresh failed: {text}
- Missing tokens in response
- OAuth error: {OAuthCallbackHandler.callback_error}
- Failed to read OAuth credentials from {path}: {e}
- No refresh token found in credentials.
AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14).
Data as JSON: /api/errors/0ede301baf2b8130.
Report an issue: GitHub.