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

  1. Inspect the raw response (curl the same URL) to see what body NVD actually returned.
  2. Bypass or fix the proxy/intercepting middlebox; try from a different network.
  3. Retry — if it was a truncated/intermittent response, a repeat call often succeeds.
  4. 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

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.

Related errors


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