decolua/9router · error
Qoder device token poll: invalid JSON response (${err.messag
Error message
Qoder device token poll: invalid JSON response (${err.message}) What it means
The poll endpoint returned HTTP 200, but the response body could not be parsed as JSON. The service reads the body as text first and JSON.parse's it; on parse failure it throws with the underlying parser message embedded. This signals an upstream contract violation or a non-JSON payload (e.g. an HTML error page served with status 200).
Source
Thrown at src/lib/oauth/services/qoder.js:132
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",
accessToken: body.token,
refreshToken: body.refresh_token || "",
userId: body.user_id || "",
expireTime: expireMs,
rawResponse: body,
};
}View on GitHub (pinned to 90b52e06ff)
Solutions
- Log the raw body alongside the error to see what was actually returned (the err.message only shows the parse offset).
- Check for transparent proxies / TLS interception that inject HTML into responses.
- Retry the poll once — intermittent gateway 200-with-empty-body can self-heal.
- If persistent, verify the Qoder endpoint URL/contract hasn't changed and update QODER_DEVICE_TOKEN_URL handling.
Defensive patterns
Strategy: try-catch
Try / catch
try {
const result = await qoder.pollDeviceToken({ nonce, codeVerifier });
} catch (e) {
if (e.message.startsWith('Qoder device token poll: invalid JSON response')) {
log.warn('non-JSON 200 from Qoder, likely proxy/interstitial', { err: e.message });
if (attempt < maxAttempts) return retryLater();
}
throw e;
} Prevention
- Check for TLS-intercepting proxies/captive portals in the deployment environment.
- Retry once on invalid-JSON 200s; they are often transient gateway artifacts.
- Log raw response bodies (via fetch wrapper) when JSON parsing failures recur.
When it happens
Trigger: Qoder returns an HTML error/captive-portal page with status 200, an empty body, or a CDN interstitial; proxy middleware rewrites the response body.
Common situations: Corporate proxies or VPNs intercepting HTTPS traffic; Qoder changing the endpoint to return plain text; intermittent gateway returning empty 200s during incidents.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- `CodeBuddy state request failed: ${await response.text()}`
- `CodeBuddy Intl state request failed: ${await response.text(
- Failed to register client: ${error}
- Failed to start device authorization: ${error}
- ${message}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/06e75522fbbcdb54.
Report an issue: GitHub.