chatboxai/chatbox · error · Error
Qwen OAuth failed: ${payload.error_description || payload.er
Error message
Qwen OAuth failed: ${payload.error_description || payload.error || response.statusText} What it means
Thrown during the Qwen OAuth2 device-flow token poll when the token endpoint returns a non-OK response whose error is neither 'authorization_pending' nor 'slow_down'. These two are the expected transient states; any other error code (e.g. 'expired_token', 'access_denied', 'invalid_grant', 'incorrect_device_code') is treated as terminal. The message surfaces whatever the server supplied: error_description preferred, then error, then response.statusText.
Source
Thrown at src/main/oauth/providers/qwen.ts:152
refreshToken: payload.refresh_token,
expiresAt: toExpiresAt(payload.expires_in),
}
}
} else {
const payload = (await response.json().catch(() => ({}))) as {
error?: string
error_description?: string
}
if (payload.error === 'authorization_pending') {
continue
}
if (payload.error === 'slow_down') {
intervalMs = Math.min(intervalMs + 2000, 10_000)
continue
}
throw new Error(`Qwen OAuth failed: ${payload.error_description || payload.error || response.statusText}`)
}
}
throw new Error('Qwen OAuth timed out waiting for authorization.')
} finally {
pendingDeviceCode = null
pendingVerifier = null
pendingIntervalMs = 2000
}
},
async refreshToken(credentials) {
if (!credentials.refreshToken) {
log.warn('[OAuth:Qwen] No refresh token available, returning existing credentials')
return credentials
}
const response = await fetch(`${QWEN_BASE_URL}/api/v1/oauth2/token`, {View on GitHub (pinned to 81571269ad)
Solutions
- Re-initiate the device flow with authenticate() so a fresh device_code + code_verifier are issued and the user gets a new verification URL.
- Check the embedded error code: 'expired_token'/'access_denied' => restart flow and have the user complete consent within ~10 min; 'incorrect_*' => verify QWEN_CLIENT_ID and that pendingDeviceCode/pendingVerifier were not reset by a prior finally block.
- Inspect response.statusText in the message — if it is non-JSON (e.g. HTML error page), treat it as a Qwen-side outage and retry with backoff rather than re-prompting.
- If reproducible, capture the raw response body once to confirm the exact OAuth error code before adjusting the flow.
Example fix
// before: terminal throw on any non-transient error
throw new Error(`Qwen OAuth failed: ${payload.error_description || payload.error || response.statusText}`)
// after: classify so 'expired_token' auto-restarts the flow
if (payload.error === 'expired_token') { throw new QwenDeviceCodeExpiredError() }
throw new Error(`Qwen OAuth failed: ${payload.error_description || payload.error || response.statusText}`) Defensive patterns
Strategy: try-catch
Validate before calling
if (!pendingDeviceCode || !pendingVerifier) { throw new Error('Device flow not initialized; call startDeviceFlow first') } Type guard
function isQwenOAuthError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('Qwen OAuth failed:')
} Try / catch
try {
return await qwenProvider.authenticate(signal)
} catch (e) {
if (isQwenOAuthError(e)) { // surface server error_description to user, offer re-auth
}
throw e
} Prevention
- Complete device-flow consent promptly within the 10-minute deadline.
- Do not reset pendingDeviceCode/pendingVerifier between polls (the finally block clears them on exit).
- Keep QWEN_CLIENT_ID constant across releases.
When it happens
Trigger: POST to ${QWEN_BASE_URL}/api/v1/oauth2/token with grant_type=urn:ietf:params:oauth:grant-type:device_code where the user denied consent (access_denied), the device_code expired (expired_token, 10 min deadline vs server's lifetime), the wrong client_id/device_code/code_verifier was sent (invalid_grant, incorrect_client, incorrect_device_code), or the server returns a malformed body that fails JSON.parse (payload becomes {} and falls through to statusText).
Common situations: User closes the browser without completing consent; user waits longer than the device_code TTL; the app was restarted mid-flow so pendingDeviceCode/pendingVerifier no longer match a live server-side code; QWEN_CLIENT_ID changed; Qwen API outage returning HTML (statusText 'Service Unavailable').
Related errors
- Qwen device authorization failed: ${text}
- Qwen OAuth timed out waiting for authorization.
- Token refresh failed: ${text}
- ${response.status} ${response.statusText}: ${text}
- MiniMax authorization failed: ${text}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/085719b6d3971926.
Report an issue: GitHub.