chatboxai/chatbox · error · Error
Device flow failed: ${raw.error}
Error message
Device flow failed: ${raw.error} What it means
Thrown inside the Copilot device-flow polling loop when GitHub's access_token endpoint returns HTTP 200 with an error field that is neither 'authorization_pending' nor 'slow_down'. These are application-level OAuth errors delivered in a 200 response, so fetchJson does not catch them; the loop's own error switch does.
Source
Thrown at src/main/oauth/providers/github-copilot.ts:125
if (raw.access_token) {
log.info('[OAuth:Copilot] GitHub access token obtained')
// Use the GitHub access token directly as the Copilot API credential
// (same approach as openllmprovider)
return {
accessToken: raw.access_token,
// No refresh token — the GitHub access token doesn't expire
// but the Copilot API session may need re-auth periodically
}
}
if (raw.error === 'authorization_pending') continue
if (raw.error === 'slow_down') {
intervalMs += 5000
continue
}
throw new Error(`Device flow failed: ${raw.error}`)
}
throw new Error('Device flow timed out')
} finally {
pendingDeviceCode = null
}
},
async refreshToken(credentials) {
// GitHub access tokens from device flow don't expire in the traditional sense.
// Just return the existing credentials.
return credentials
},
}
View on GitHub (pinned to 81571269ad)
Solutions
- Inspect raw.error: 'expired_token' and 'access_denied' should restart the flow (startDeviceFlow), not retry the same device_code.
- For 'incorrect_client_credentials' / 'unsupported_grant_type' / 'device_flow_disabled', surface a config error — no amount of retrying will help.
- Surface a user-facing message: 'Authorization expired, please try again' for expired_token, 'Access was denied' for access_denied.
Example fix
// before
throw new Error(`Device flow failed: ${raw.error}`)
// after
if (raw.error === 'expired_token' || raw.error === 'access_denied') {
throw new Error(raw.error === 'expired_token' ? 'Device code expired. Restart login.' : 'User denied the login request.')
}
throw new Error(`Device flow failed: ${raw.error}`) Defensive patterns
Strategy: try-catch
Type guard
type DeviceFlowError = 'expired_token' | 'access_denied' | 'incorrect_client_credentials' | 'unsupported_grant_type' | 'device_flow_disabled'
function isTerminalDeviceError(error: unknown): error is DeviceFlowError {
return typeof error === 'string' && ['expired_token','access_denied','incorrect_client_credentials','unsupported_grant_type','device_flow_disabled'].includes(error as string)
} Try / catch
try {
return await provider.waitForToken(signal)
} catch (e) {
const msg = String(e)
if (/expired_token/i.test(msg) || /access_denied/i.test(msg)) {
// restartable: user-driven causes
const fresh = await provider.startDeviceFlow()
throw new ReauthRequiredError(fresh)
}
if (/incorrect_client|unsupported_grant|device_flow_disabled/i.test(msg)) {
throw new Error('GitHub device flow misconfigured for this OAuth App.')
}
throw e
} Prevention
- Make sure the user authorizes within the device-code lifetime (typically ~15 min).
- Confirm the OAuth App has device flow enabled in its GitHub settings.
- Restart the flow on expired_token / access_denied rather than retrying the same device_code.
When it happens
Trigger: error='expired_token' (user didn't authorize within the device-code lifetime), 'access_denied' (user explicitly denied the request at github.com/login/device), 'incorrect_client_credentials', 'unsupported_grant_type', or 'device_flow_disabled' for the client.
Common situations: User walked away past the ~15-minute device-code expiry; user clicked 'Cancel' on GitHub's device confirmation page; the OAuth App has device flow disabled in its settings; CLIENT_ID mismatch produces incorrect_client_credentials.
Related errors
- ${response.status} ${response.statusText}: ${text}
- Device flow timed out
- MiniMax OAuth failed: ${errorMessage || text}
- MiniMax authorization failed: ${text}
- MiniMax OAuth timed out waiting for authorization.
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/6fe5fc317f172431.
Report an issue: GitHub.