jackwener/OpenCLI · error · CommandExecutionError
Malformed JSON from Stack Exchange API for ${label}: ${detai
Error message
Malformed JSON from Stack Exchange API for ${label}: ${detail} What it means
After a successful HTTP response, fetchJson parses the body with res.json(); if parsing throws it wraps the parse error detail in a CommandExecutionError. This means the API returned HTTP 200 (or at least non-404/non-error) but the body was not valid JSON, which the library interprets as a transient outage or an intermediary corrupting the response.
Source
Thrown at clis/stackoverflow/read.js:54
`Network failure fetching ${label}: ${detail}`,
'Check connectivity to api.stackexchange.com',
);
}
if (res.status === 404) {
throw new EmptyResultError(label, `${label} not found`);
}
if (!res.ok) {
throw new CommandExecutionError(
`Stack Exchange API HTTP ${res.status} for ${label}`,
'Check the question id and quota (300/day per IP)',
);
}
let json;
try {
json = await res.json();
} catch (e) {
const detail = e instanceof Error ? e.message : String(e);
throw new CommandExecutionError(
`Malformed JSON from Stack Exchange API for ${label}: ${detail}`,
'The API returned a non-JSON body — likely a transient outage',
);
}
if (json && json.error_id) {
throw new CommandExecutionError(
`Stack Exchange API error ${json.error_id} (${json.error_name}) for ${label}: ${json.error_message || ''}`,
'Common causes: invalid filter, throttled, or quota exhausted',
);
}
return json;
}
/**
* CLI args may arrive as strings (`--limit 5` → `'5'`) when not coerced by the
* arg type system. Coerce-then-validate so `Number.isInteger` actually catches
* the bad cases, and reject NaN explicitly.
*/View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the request — it is usually a transient outage or interception
- Inspect the raw response: curl -s https://api.stackexchange.com/2.2/questions/<id>?site=stackoverflow | head -c 200 to see what is actually returned
- Check whether a proxy/captive portal is intercepting the connection (look for HTML in the body)
- Verify TLS is not being MITM'd by VPN/security software; bypass or trust its certificate
Example fix
async function safeFetchJson(url, label) {
const res = await fetch(url);
const text = await res.text();
try {
return JSON.parse(text);
} catch (e) {
throw new Error(`Non-JSON body for ${label}: ${text.slice(0, 120)}`);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
async function looksLikeJsonResponse(url) {
const res = await fetch(url);
const ct = res.headers.get('content-type') ?? '';
return ct.includes('application/json');
}
// warn if false before parsing: intercepting proxy or HTML error page likely Try / catch
try {
const data = await qData(id);
} catch (e) {
if (/Malformed JSON from Stack Exchange API/.test(e?.message ?? '')) {
console.error('Non-JSON body — transient outage or proxy interference. Retrying in 30s...');
await new Promise(r => setTimeout(r, 30000));
} else {
throw e;
}
} Prevention
- Retry on malformed JSON — it is usually transient, not a bug in your code
- Bypass or properly configure TLS-inspecting proxies/captive portals
- Spot-check raw responses with curl when errors cluster in time (outage signature)
- Prefer reading res.text() then JSON.parse to get the offending body in your own error messages
When it happens
Trigger: res.json() rejects on any caller's response: an HTML error/maintenance page returned with status 200, a proxy or captive portal injecting a login page, truncated/garbled response body, or wrong Content-Type body from an intercepting middlebox.
Common situations: Corporate SSL-inspection proxies replacing the JSON with an HTML warning page; hotel/airport captive portals intercepting HTTPS; Stack Exchange returning a compressed or partial body during brief incidents; local MITM debugging tools breaking the stream.
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
- Chess.com callback returned malformed JSON for ${url}: ${err
- mdn search returned malformed JSON: ${err?.message ?? err}
- nvd cve returned malformed JSON: ${err?.message ?? err}
- ${label} returned malformed JSON: ${err?.message ?? err}
- ${label} returned malformed JSON: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/16cb2aea40f4a6ec.
Report an issue: GitHub.