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

  1. Retry the same rfc/doc command; transient truncation or a proxy hiccup is the most common cause.
  2. Check network/proxy settings: run `curl -s -H 'accept: application/json' <url>` and inspect whether the body is JSON or an HTML page.
  3. Disable HTTPS interception/inspection on the proxy for datatracker.ietf.org, or bypass the proxy for that host (e.g. set NO_PROXY).
  4. 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

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

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/923048227cd0cc1e. Report an issue: GitHub.