jackwener/OpenCLI · error · CommandExecutionError

${label} returned malformed JSON: ${err?.message ?? err}

Error message

${label} returned malformed JSON: ${err?.message ?? err}

What it means

This CommandExecutionError is thrown by nugetFetch in clis/nuget/utils.js when resp.json() fails — the server returned an HTTP-ok response whose body is not valid JSON (or the connection was truncated mid-body). The library expects all NuGet endpoints to return JSON (it sends accept: application/json) so a non-JSON body indicates an intercepted or malformed response.

Source

Thrown at clis/nuget/utils.js:73

            `${label} request failed: ${err?.message ?? err}`,
            'Check that api.nuget.org is reachable from this network.',
        );
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `NuGet 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;
}

export function joinTags(tags) {
    if (!Array.isArray(tags)) return '';
    return tags.filter((t) => typeof t === 'string' && t.trim()).join(', ');
}

export function joinAuthors(authors) {
    if (Array.isArray(authors)) return authors.filter((a) => typeof a === 'string' && a.trim()).join(', ');
    if (typeof authors === 'string') return authors.trim();
    return '';
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the raw response (curl the URL) to see what body is actually returned
  2. Bypass or reconfigure the intercepting proxy / complete captive-portal login
  3. Retry the request — truncation is often transient
  4. Check NODE_EXTRA_CA_CERTS / TLS setup if a corporate appliance is rewriting traffic

Example fix

// before
const data = await nugetFetch(url, 'search'); // throws on HTML body
// after
try {
  const data = await nugetFetch(url, 'search');
} catch (e) {
  if (String(e.message).includes('malformed JSON')) {
    // fall back or retry — likely proxy/captive portal
  }
  throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

null

Try / catch

try {
  const data = await nugetFetch(url, 'search');
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('malformed JSON')) {
    await sleep(1000);
    return nugetFetch(url, 'search'); // truncated/proxied response; retry
  }
  throw e;
}

Prevention

When it happens

Trigger: A proxy or captive portal returning an HTML login/error page with status 200; TLS-intercepting middleboxes rewriting responses; truncated response bodies on flaky networks; a CDN edge returning an HTML error page.

Common situations: Hotel/airport Wi-Fi captive portals; corporate SSL inspection appliances; very large search responses cut off by an aggressive proxy timeout.

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/54caecbf7983865e. Report an issue: GitHub.