jackwener/OpenCLI · error · CommandExecutionError
${label} returned malformed JSON: ${err?.message ?? err}
Error message
${label} returned malformed JSON: ${err?.message ?? err} What it means
gemsFetch (clis/rubygems/utils.js:75) calls resp.json() on every successful RubyGems response; if the body cannot be parsed as JSON it rethrows as a CommandExecutionError including the underlying parse message. This guards against endpoints (or intermediaries) returning HTML/error pages with a 200 status.
Source
Thrown at clis/rubygems/utils.js:75
}
if (resp.status === 404) {
throw new EmptyResultError(label, `RubyGems returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'RubyGems throttles bursts; wait a few seconds and retry.',
);
}
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;
}
/** Trim "2026-03-24T20:27:42.098Z" → "2026-03-24T20:27:42Z" so timestamps share a uniform precision. */
export function trimDate(value) {
const s = String(value ?? '').trim();
if (!s) return null;
const noFrac = s.replace(/\.\d+/, '');
return noFrac.endsWith('Z') ? noFrac : `${noFrac}Z`;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw response with curl -i to see what body rubygems.org (or an intermediary) actually returned.
- Disable/inspect proxies, VPNs, or captive portals intercepting HTTPS traffic.
- Retry — truncated bodies from flaky networks often succeed on a second attempt.
- Verify the URL is hitting rubygems.org/api/v1 and not a redirect to an HTML page.
- If it persists, report/trace at the network layer; the parse message in the error identifies the exact JSON syntax problem.
Example fix
// before
const body = await gemsFetch(`${GEMS_BASE}/versions/${name}.json`, 'rubygems versions');
// after
let body;
try {
body = await gemsFetch(`${GEMS_BASE}/versions/${name}.json`, 'rubygems versions');
} catch (err) {
if (/malformed JSON/.test(err.message)) {
// fetch raw text via curl to inspect; check proxy/captive portal
}
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
const resp = await fetch(url, { headers: { accept: 'application/json' } });
const text = await resp.text();
if (resp.ok && !text.trim().startsWith('{') && !text.trim().startsWith('[')) {
throw new Error('Response is not JSON (likely an HTML proxy/captive-portal page)');
} Type guard
function isMalformedJsonError(err) {
return err instanceof Error && /malformed JSON/.test(err.message);
} Try / catch
try {
body = await gemsFetch(url, 'rubygems versions');
} catch (err) {
if (isMalformedJsonError(err)) {
// log network context: proxy env vars, then retry once
delete process.env.HTTP_PROXY;
body = await gemsFetch(url, 'rubygems versions');
} else throw err;
} Prevention
- Check for HTTP_PROXY/HTTPS_PROXY settings and captive portals when errors cluster on one network.
- Always send accept: application/json and inspect content-type on failures.
- For large payloads, retry on truncation-related parse errors.
- curl -i the failing URL to capture the raw body for diagnosis.
When it happens
Trigger: resp.ok was true but resp.json() threw — the body was HTML (proxy/captive-portal/login page), empty, truncated, or otherwise not JSON despite the accept: application/json header.
Common situations: Corporate proxies or Wi-Fi captive portals injecting HTML interstitials; a CDN error page served with HTTP 200; network truncation of large responses (e.g. big version lists); misconfigured transparent proxies rewriting the response.
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
- archive search returned malformed JSON: ${error?.message ||
- archive wayback returned malformed JSON: ${error?.message ||
- ${label} returned malformed JSON: ${err?.message ?? err}
- hf datasets returned malformed JSON: ${error?.message || err
- hf models returned malformed JSON: ${error?.message || error
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1b3759b4b205fc82.
Report an issue: GitHub.