jackwener/OpenCLI · error · CommandExecutionError
${label} returned malformed JSON: ${err?.message ?? err}
Error message
${label} returned malformed JSON: ${err?.message ?? err} What it means
rfcFetch in clis/rfc/utils.js fetches a URL from the IETF datatracker API and calls resp.json() on the response. When the HTTP 200 body cannot be parsed as JSON (SyntaxError from resp.json()), it is re-thrown as a CommandExecutionError with the label and the underlying parse message. The library throws this because a non-JSON body (HTML error page, proxy interception, truncation) means the datatracker response is unusable.
Source
Thrown at clis/rfc/utils.js:59
`${label} request failed: ${err?.message ?? err}`,
'Check that datatracker.ietf.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `IETF datatracker returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(`${label} returned HTTP 429 (rate limited)`);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
}
let body;
try {
body = await resp.json();
}
catch (err) {
throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
}
return body;
}
// IETF datatracker timestamps are like "2022-02-19 08:46:51" (no T, no Z)
// or ISO with offset like "2016-07-08T21:03:52+00:00". Normalise to YYYY-MM-DD.
export function trimDate(value) {
const s = String(value ?? '').trim();
if (!s) return null;
// Take the first 10 chars only if they form a YYYY-MM-DD prefix.
if (/^\d{4}-\d{2}-\d{2}/.test(s)) return s.slice(0, 10);
return null;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the same rfc/doc command; transient truncation or a proxy hiccup is the most common cause.
- Check network/proxy settings: run `curl -s -H 'accept: application/json' <url>` and inspect whether the body is JSON or an HTML page.
- Disable HTTPS interception/inspection on the proxy for datatracker.ietf.org, or bypass the proxy for that host (e.g. set NO_PROXY).
- Wait and retry later if datatracker is degraded; if it persists, check the datatracker status or fall back to rfc-editor.org data.
Example fix
// before: command dies with malformed-JSON error
await doc({ number: 9000 });
// after: caller retries with fallback
try {
const info = await doc({ number: 9000 });
} catch (e) {
if (/malformed JSON/.test(e.message)) {
// inspect raw body / retry once
}
} Defensive patterns
Strategy: try-catch
Validate before calling
const resp = await fetch(url, { headers: { accept: 'application/json' } });
const text = await resp.text();
if (!text.trim().startsWith('{') && !text.trim().startsWith('[')) {
throw new Error('datatracker returned non-JSON body: ' + text.slice(0, 120));
} Type guard
function isJsonObject(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
const doc = await rfcFetch(url, 'rfc doc');
} catch (e) {
if (/malformed JSON/.test(e.message)) {
// inspect raw response / bypass proxy / retry once
} else throw e;
} Prevention
- Verify `curl -s <url> | head -c 200` returns JSON before blaming the library.
- Bypass corporate proxies for datatracker.ietf.org (NO_PROXY) to avoid HTML interception pages.
- Treat any 200-with-HTML as a network-layer problem, not a client bug.
When it happens
Trigger: rfcFetch (called by doc commands) receives a 2xx response whose body is not valid JSON: resp.json() throws and line 59 converts it to `${label} returned malformed JSON: ...`.
Common situations: Corporate proxy or captive portal returning an HTML login page with HTTP 200; datatracker serving an HTML error/interstitial page; response truncated by a flaky network or aggressive proxy; hitting a mirror or misconfigured RFC_BASE that returns HTML.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- stack exchange returned malformed JSON: ${error?.message ||
- ${label} returned a non-JSON response
- archive snapshots returned malformed JSON: ${error?.message
- `${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/923048227cd0cc1e.
Report an issue: GitHub.