decolua/9router · error
${message}
Error message
${message} What it means
Thrown when Qoder's device-token poll endpoint answers with a non-2xx status. The message is 'Qoder device token poll failed: HTTP <status>', upgraded to include the upstream JSON 'message' field when the body parses as JSON. Per the service contract, upstream returns 202/404 while the user is still authorizing; any other non-ok status reaching this throw is a terminal failure of the device flow.
Source
Thrown at src/lib/oauth/services/qoder.js:125
"User-Agent": "Go-http-client/2.0",
},
});
// Pending — server has registered the device code but the user hasn't
// finished the browser flow yet. Both 202 and 404 mean "keep polling".
if (response.status === 202 || response.status === 404) {
return { status: "pending" };
}
const text = await response.text();
if (!response.ok) {
let message = `Qoder device token poll failed: HTTP ${response.status}`;
try {
const body = JSON.parse(text);
if (body.message) message = `Qoder device token poll failed: ${body.message}`;
} catch {}
throw new Error(message);
}
let body;
try {
body = JSON.parse(text);
} catch (err) {
throw new Error(`Qoder device token poll: invalid JSON response (${err.message})`);
}
// Defensive: 200 + empty token means the upstream changed shape.
if (!body.token) {
throw new Error("Qoder device token poll returned 200 but no token");
}
const expireMs = QoderService.parseExpiry(body.expires_at, body.expires_in);
return {
status: "ok",View on GitHub (pinned to 90b52e06ff)
Solutions
- Read the included upstream message in the error text to identify the exact cause (e.g. expired nonce vs unauthorized).
- Treat 202/404 as 'keep waiting' in your polling loop and only surface other statuses as fatal.
- Restart the device flow (new nonce + code verifier) if the poll indicates expiry or invalid state.
- Check Qoder service status / network connectivity if the status is 5xx.
Example fix
// before
const t = await qoder.pollDeviceToken({ nonce, codeVerifier }); // throws on 404 while waiting
// after
try {
const t = await qoder.pollDeviceToken({ nonce, codeVerifier });
} catch (e) {
if (/HTTP (202|404)/.test(e.message)) return continuePolling();
throw e;
} Defensive patterns
Strategy: retry
Try / catch
try {
const result = await qoder.pollDeviceToken({ nonce, codeVerifier });
} catch (e) {
if (/HTTP 202|HTTP 404/.test(e.message)) { await sleep(pollInterval); continue; } // still waiting
if (/HTTP 5\d\d/.test(e.message)) { await sleep(backoff); continue; } // transient upstream
throw e; // 400/401/403: state is bad, restart device flow
} Prevention
- Implement a bounded polling loop that treats 202/404 as pending, not fatal.
- Restart the device flow when the poll indicates expiry instead of retrying a dead nonce.
- Surface the upstream message (already embedded) to logs for diagnosis.
When it happens
Trigger: GET to QODER_DEVICE_TOKEN_URL returns 400/401/403/500 etc. — e.g. an expired or invalid nonce, wrong verifier (PKCE mismatch), or Qoder outage. Note 202/404 while waiting are expected polling states, not this error, if handled by the caller's retry loop.
Common situations: Polling after the device code expired; reusing a nonce from a previous flow; Qoder API version change altering the endpoint contract; corporate proxy returning 502 with an HTML body (which keeps the generic HTTP status message).
Related errors
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
- onboardUser HTTP ${response.status}: ${errorText.slice(0, 20
- `CodeBuddy state request failed: ${await response.text()}`
- `CodeBuddy Intl state request failed: ${await response.text(
- Failed to save tokens
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/2a42b0c2f6f342c0.
Report an issue: GitHub.