xtekky/gpt4free · error · Exception

Device authorization error: {resp_json.get('error')} - {resp

Error message

Device authorization error: {resp_json.get('error')} - {resp_json.get('error_description')}

What it means

Raised by QwenOAuth2.startDeviceAuthorization (qwenOAuth2.py:122) when the device-authorization endpoint answers HTTP 200 but the response fails isDeviceAuthorizationSuccess() — i.e. it carries an OAuth 'error'/'error_description' pair (such as invalid_client or access_denied) instead of a device_code. A 200-with-error body means the request reached the server but was semantically rejected.

Source

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

            "code_challenge_method": options["code_challenge_method"],
        }
        async with aiohttp.ClientSession(headers={"user-agent": ""}) as session:
            async with session.post(
                QWEN_OAUTH_DEVICE_CODE_ENDPOINT,
                headers={
                    "Content-Type": "application/x-www-form-urlencoded",
                    "Accept": "application/json",
                    "x-request-id": str(uuid.uuid4()),
                },
                data=object_to_urlencoded(body_data),
            ) as resp:
                resp_json = await resp.json()
                if resp.status != 200:
                    raise Exception(
                        f"Device authorization failed {resp.status}: {resp_json}"
                    )
                if not isDeviceAuthorizationSuccess(resp_json):
                    raise Exception(
                        f"Device authorization error: {resp_json.get('error')} - {resp_json.get('error_description')}"
                    )
                return resp_json

    async def pollDeviceToken(self, options: dict) -> Union[Dict, ErrorDataDict]:
        body_data = {
            "grant_type": QWEN_OAUTH_GRANT_TYPE,
            "client_id": QWEN_OAUTH_CLIENT_ID,
            "device_code": options["device_code"],
            "code_verifier": options["code_verifier"],
        }
        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",
                },

View on GitHub (pinned to 973504e177)

Solutions

  1. Upgrade g4f to pick up the current Qwen OAuth client constants
  2. Log resp_json.get('error') — invalid_client points at client_id skew, access_denied at policy blocks
  3. Retry once to rule out a transient gateway hiccup, then fall back to another provider
Defensive patterns

Strategy: try-catch

Try / catch

try:
    resp = await oauth.startDeviceAuthorization(options)
except Exception as exc:
    # message embeds error/error_description from a 200 body
    if "invalid_client" in str(exc):
        raise RuntimeError("g4f too old for Qwen OAuth; upgrade") from exc
    raise

Prevention

When it happens

Trigger: The endpoint returns JSON like {'error': 'invalid_client', 'error_description': ...} with status 200; triggered by a wrong/revoked QWEN_OAUTH_CLIENT_ID, disallowed grant_type, or API-gateway wrappers that always return 200.

Common situations: Qwen rotates the public client_id embedded in g4f and old versions fail; region-specific auth endpoints rejecting the flow; responses routed through gateways that normalize status codes to 200.

Related errors


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