xtekky/gpt4free · critical · Exception

Refresh token expired or invalid

Error message

Refresh token expired or invalid

What it means

Raised by QwenOAuth2.refreshAccessToken (qwenOAuth2.py:177) when the token endpoint returns HTTP 400 during a refresh_token grant — the OAuth-standard signal that the refresh token is expired, revoked, or invalid. Crucially, the handler first resets self.credentials to an empty QwenCredentials(), so the stored session is destroyed and interactive re-authentication is required.

Source

Thrown at g4f/Provider/qwen/qwenOAuth2.py:177

            "grant_type": "refresh_token",
            "refresh_token": self.credentials["refresh_token"],
            "client_id": QWEN_OAUTH_CLIENT_ID,
        }
        async with aiohttp.ClientSession(headers={"user-agent": ""}) as session:
            async with session.post(
                QWEN_OAUTH_TOKEN_ENDPOINT,
                headers={
                    "Content-Type": "application/x-www-form-urlencoded",
                    "Accept": "application/json",
                },
                data=object_to_urlencoded(body_data),
            ) as resp:
                resp_json = await resp.json()
                if resp.status != 200:
                    if resp.status == 400:
                        # Handle token expiration
                        self.credentials = QwenCredentials()
                        raise Exception("Refresh token expired or invalid")
                    raise Exception(f"Token refresh failed {resp.status}: {resp_json}")
                return resp_json

    def isTokenValid(self, credentials: QwenCredentials) -> bool:
        if not credentials.get("expiry_date"):
            return False
        return time.time() * 1000 < credentials["expiry_date"] - TOKEN_REFRESH_BUFFER_MS

View on GitHub (pinned to 973504e177)

Solutions

  1. Re-run the Qwen device authorization flow — the wiped credentials cannot be recovered
  2. Prevent concurrent refreshes (the shared token manager's file lock exists for this; ensure a single instance refreshes)
  3. Refresh proactively before expiry rather than after, so tokens rotate cleanly
  4. If single-use refresh tokens are the norm, persist the new refresh_token immediately after each refresh
Defensive patterns

Strategy: fallback

Try / catch

try:
    resp = await qwen_client.refreshAccessToken()
except Exception as exc:
    if "Refresh token expired or invalid" in str(exc):
        # credentials were wiped; interactive re-auth is the only path
        await start_qwen_device_login()
    else:
        raise

Prevention

When it happens

Trigger: POST to QWEN_OAUTH_TOKEN_ENDPOINT with grant_type=refresh_token returns 400: refresh token past its lifetime, revoked server-side (password change / logout all devices), or single-use token already consumed by a concurrent process.

Common situations: Credentials stored long ago and Qwen's refresh-token TTL elapsed; two g4f processes raced and one consumed the rotating refresh token; account security event revoked grants.

Understand the failure class

Related errors


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