xtekky/gpt4free · error · Exception

No refresh token

Error message

No refresh token

What it means

Raised by QwenOAuth2.refreshAccessToken (qwenOAuth2.py:157) when refresh is attempted while the stored credentials contain no refresh_token. It is a pure precondition failure: the client was asked to refresh an authorization it never had (or no longer has).

Source

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

                    "Accept": "application/json",
                },
                data=object_to_urlencoded(body_data),
            ) as resp:
                resp_json = await resp.json()
                if resp.status != 200:
                    # Check for OAuth RFC 8628 responses
                    if resp.status == 400:
                        if "error" in resp_json:
                            if resp_json["error"] == "authorization_pending":
                                return {"status": "pending"}
                            if resp_json["error"] == "slow_down":
                                return {"status": "pending", "slowDown": True}
                    raise Exception(f"Token poll failed {resp.status}: {resp_json}")
                return resp_json

    async def refreshAccessToken(self) -> Union[Dict, ErrorDataDict]:
        if not self.credentials.get("refresh_token"):
            raise Exception("No refresh token")
        body_data = {
            "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

View on GitHub (pinned to 973504e177)

Solutions

  1. Re-run the Qwen device authorization flow to obtain fresh tokens
  2. Check credentials storage: ensure 'refresh_token' is present before enabling Qwen
  3. Guard callers with an upfront check for refresh_token before requesting a refresh

Example fix

// before
resp = await qwen_client.refreshAccessToken()  # may raise No refresh token

// after
creds = qwen_client.getCredentials()
if not creds.get("refresh_token"):
    raise RuntimeError("re-authentication required")
resp = await qwen_client.refreshAccessToken()
Defensive patterns

Strategy: validation

Validate before calling

creds = qwen_client.getCredentials()
assert creds.get("refresh_token"), "cannot refresh without a refresh token"
resp = await qwen_client.refreshAccessToken()

Type guard

def can_refresh(creds: dict) -> bool:
    return isinstance(creds, dict) and isinstance(creds.get("refresh_token"), str) and len(creds["refresh_token"]) > 0

Try / catch

try:
    resp = await qwen_client.refreshAccessToken()
except Exception as exc:
    if "No refresh token" in str(exc):
        await start_qwen_device_login()
    else:
        raise

Prevention

When it happens

Trigger: Calling refreshAccessToken() (directly or via the token manager) after setCredentials() with a dict lacking 'refresh_token' — e.g. after qwenOAuth2.py:177 reset credentials to empty QwenCredentials() on a prior 400.

Common situations: Refresh token previously expired and credentials were wiped, then another refresh is attempted; credentials file hand-created with only an access_token; race where two processes refresh concurrently and one clears state.

Related errors


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