jackwener/OpenCLI · error · CommandExecutionError
nvd cve returned malformed JSON: ${err?.message ?? err}
Error message
nvd cve returned malformed JSON: ${err?.message ?? err} What it means
Thrown when resp.json() fails to parse the NVD response body, wrapped as a CommandExecutionError with the parse error message. This means NVD returned a 2xx response that is not valid JSON — e.g. an HTML error/interstitial page from a proxy or CDN, or a truncated response.
Source
Thrown at clis/nvd/cve.js:98
'nvd cve returned HTTP 403',
'NVD enforces aggressive rate limits without an API key. Wait, then retry or set NVD_API_KEY (not yet wired).',
);
}
if (resp.status === 429) {
throw new CommandExecutionError(
'nvd cve returned HTTP 429 (rate limited)',
'NVD throttles unauthenticated traffic; wait several seconds before retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`nvd cve returned HTTP ${resp.status}`);
}
let body;
try {
body = await resp.json();
}
catch (err) {
throw new CommandExecutionError(`nvd cve returned malformed JSON: ${err?.message ?? err}`);
}
const list = Array.isArray(body?.vulnerabilities) ? body.vulnerabilities : [];
const cve = list[0]?.cve;
if (!cve || !cve.id) {
throw new EmptyResultError('nvd cve', `NVD has no record for "${id}".`);
}
const cvss = pickPrimaryCvss(cve.metrics);
const cvssData = cvss?.cvssData ?? {};
return [{
id: String(cve.id),
published: String(cve.published ?? '').slice(0, 10),
lastModified: String(cve.lastModified ?? '').slice(0, 10),
vulnStatus: String(cve.vulnStatus ?? ''),
baseScore: cvssData.baseScore != null ? Number(cvssData.baseScore) : null,
severity: String(cvssData.baseSeverity ?? cvss?.baseSeverity ?? ''),
attackVector: String(cvssData.attackVector ?? ''),
cwe: joinCwes(cve.weaknesses),
kevAdded: cve.cisaExploitAdd ? String(cve.cisaExploitAdd).slice(0, 10) : '',View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw response (curl the same URL) to see what body NVD actually returned.
- Bypass or fix the proxy/intercepting middlebox; try from a different network.
- Retry — if it was a truncated/intermittent response, a repeat call often succeeds.
- Check that no custom NVD_BASE override points at a non-API endpoint.
Defensive patterns
Strategy: try-catch
Try / catch
try { return await nvdCve(id); } catch (e) { if (e.message.includes('malformed JSON')) { logRawResponseForDebugging(); throw new Error('NVD returned non-JSON (proxy/portal?)'); } throw e; } Prevention
- Detect captive portals / proxy HTML injection before API calls.
- Compare a curl of the endpoint with the library's request when debugging.
- Prefer TLS-passthrough over TLS-inspecting proxies for API traffic.
- Retry once automatically — truncation is often transient.
When it happens
Trigger: A cveId lookup where the 2xx body is not JSON: captive portals or proxies injecting HTML, NVD returning an empty/HTML maintenance page with 200, or a response body cut off mid-stream.
Common situations: Working behind corporate proxies that rewrite responses, hotel/airport Wi-Fi captive portals, TLS-inspecting middleboxes, or NVD instability during high load.
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
- Malformed JSON from Stack Exchange API for ${label}: ${detai
- ${label} returned a non-JSON response
- Chess.com callback returned malformed JSON for ${url}: ${err
- Ctrip flight API returned invalid JSON
- hf paper returned malformed JSON: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/da724b269fb44fd0.
Report an issue: GitHub.