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

  1. Re-initiate the device flow with authenticate() so a fresh device_code + code_verifier are issued and the user gets a new verification URL.
  2. 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.
  3. 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.
  4. 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

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


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/085719b6d3971926. Report an issue: GitHub.