chatboxai/chatbox · error · Error
Qwen device authorization failed: ${text}
Error message
Qwen device authorization failed: ${text} What it means
Thrown by Qwen's startDeviceFlow() when the initial POST to chat.qwen.ai/api/v1/oauth2/device/code returns non-2xx. The raw response body is interpolated. This is the first call that registers the device flow and yields the user_code and verification_uri; failure here prevents polling from ever starting.
Source
Thrown at src/main/oauth/providers/qwen.ts:73
const response = await fetch(`${QWEN_BASE_URL}/api/v1/oauth2/device/code`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'x-request-id': randomUUID(),
},
body: new URLSearchParams({
client_id: QWEN_CLIENT_ID,
scope: 'openid profile email model.completion',
code_challenge: challenge,
code_challenge_method: 'S256',
}).toString(),
})
if (!response.ok) {
const text = await response.text()
throw new Error(`Qwen device authorization failed: ${text}`)
}
const payload = (await response.json()) as {
device_code: string
user_code: string
verification_uri: string
verification_uri_complete?: string
expires_in?: number
interval?: number
}
pendingDeviceCode = payload.device_code
pendingVerifier = verifier
pendingIntervalMs = payload.interval ? payload.interval * 1000 : 2000
return {
userCode: payload.user_code,
verificationUri: payload.verification_uri_complete || payload.verification_uri,View on GitHub (pinned to 81571269ad)
Solutions
- Read the interpolated body for Qwen's reason — 4xx typically means client/scope/PKCE mismatch, 5xx means retry.
- Verify QWEN_CLIENT_ID and QWEN_BASE_URL against the current Qwen portal contract.
- Confirm code_challenge is base64url SHA-256 of the verifier and code_challenge_method is 'S256'.
- For 5xx or network errors, retry once with backoff before surfacing.
Example fix
// before
if (!response.ok) {
const text = await response.text()
throw new Error(`Qwen device authorization failed: ${text}`)
}
// after
if (!response.ok) {
const text = await response.text()
log.error('[OAuth:Qwen] device code request failed', response.status, text)
if (response.status >= 500) throw new TransientError('Qwen unavailable, retry')
throw new Error(`Qwen device authorization failed (${response.status}): ${text}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Sanity-check PKCE before the request to Qwen.
function assertQwenPkce(verifier: string, challenge: string) {
if (verifier.length < 32) throw new Error('verifier too short')
if (!/^[A-Za-z0-9_-]+$/.test(challenge)) throw new Error('challenge must be base64url')
} Try / catch
try {
return await provider.startDeviceFlow()
} catch (e) {
const msg = String(e)
if (/Qwen device authorization failed/i.test(msg)) {
if (/5\d\d|network|fetch/i.test(msg)) return await provider.startDeviceFlow() // transient retry
throw new Error('Qwen rejected the device request — check client_id, scope, base URL, and PKCE.')
}
throw e
} Prevention
- Verify QWEN_CLIENT_ID and QWEN_BASE_URL against the current Qwen portal contract after each release.
- Generate the challenge as base64url SHA-256 of the verifier with method S256.
- Keep a unique x-request-id per request to aid server-side tracing.
- Retry only on 5xx/network; 4xx indicates config or contract problems.
When it happens
Trigger: QWEN_CLIENT_ID (f0304373b74a44d2b584a3fb70ca9e56) rejected by Qwen; requested scope (openid profile email model.completion) not permitted for the client; PKCE code_challenge malformed or not S256; QWEN_BASE_URL changed; x-request-id header rejected; Qwen API outage or rate limit.
Common situations: Qwen rotated the public client_id; the base URL shifted (e.g. regional endpoint); a corporate proxy rewrote the form body or stripped the x-request-id header; the scope set was changed server-side.
Related errors
- MiniMax authorization failed: ${text}
- Qwen OAuth failed: ${payload.error_description || payload.er
- Token exchange failed: ${error}
- ${response.status} ${response.statusText}: ${text}
- Token exchange failed: ${response.status}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/e9d4c9801c4f67ba.
Report an issue: GitHub.