xtekky/gpt4free · error · RuntimeError

Missing tokens in response

Error message

Missing tokens in response

What it means

The token endpoint returned 200 but the JSON lacked access_token or refresh_token. access_token absence is anomalous (see error 101), but a missing refresh_token is the classic Google OAuth outcome when the consent grant did not request/force offline access — Google only issues a refresh_token the first time the user consents, unless approval_prompt=force / prompt=consent is used.

Source

Thrown at g4f/Provider/needs_auth/Antigravity.py:657

                "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()
                    email = user_info.get("email")

            # Discover project ID if not provided
            effective_project_id = project_id
            if not effective_project_id:
                effective_project_id = await cls._fetch_project_id(
                    session, access_token
                )

View on GitHub (pinned to 973504e177)

Solutions

  1. Revoke the app in Google Account > Security > Third-party access, then re-run login so Google issues a fresh refresh_token.
  2. Ensure the authorization URL includes access_type=offline and prompt=consent (as built by build_authorization_url) so a refresh token is always returned.
  3. Do not reuse an authorization code from an earlier session; start a new flow.

Example fix

# before: silent re-consent returns no refresh_token
url = "https://accounts.google.com/o/oauth2/v2/auth?...&response_type=code"  # no offline access

# after: force offline access and fresh consent
url = ("https://accounts.google.com/o/oauth2/v2/auth?"
       "...&response_type=code&access_type=offline&prompt=consent")
Defensive patterns

Strategy: try-catch

Try / catch

try:
    tokens = await Antigravity.exchange_code_for_tokens(code, state)
except RuntimeError as e:
    if "Missing tokens in response" in str(e):
        # most often missing refresh_token: revoke app grant, re-login with prompt=consent
        raise

Prevention

When it happens

Trigger: Authorization request built without access_type=offline or without forcing re-consent, so Google returns only an access token; or the user had previously granted and Google suppresses the refresh_token on subsequent grants.

Common situations: Re-running login after revoking only the token (not the app grant) in the Google account; authorization URL parameters altered to drop access_type=offline; SSO/Workspace policies restricting offline access.

Related errors


AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14). Data as JSON: /api/errors/3e3cce725fb782a9. Report an issue: GitHub.