jackwener/OpenCLI · error · CommandExecutionError

Malformed JSON from Stack Exchange API for ${label}: ${detai

Error message

Malformed JSON from Stack Exchange API for ${label}: ${detail}

What it means

After a successful HTTP response, fetchJson parses the body with res.json(); if parsing throws it wraps the parse error detail in a CommandExecutionError. This means the API returned HTTP 200 (or at least non-404/non-error) but the body was not valid JSON, which the library interprets as a transient outage or an intermediary corrupting the response.

Source

Thrown at clis/stackoverflow/read.js:54

            `Network failure fetching ${label}: ${detail}`,
            'Check connectivity to api.stackexchange.com',
        );
    }
    if (res.status === 404) {
        throw new EmptyResultError(label, `${label} not found`);
    }
    if (!res.ok) {
        throw new CommandExecutionError(
            `Stack Exchange API HTTP ${res.status} for ${label}`,
            'Check the question id and quota (300/day per IP)',
        );
    }
    let json;
    try {
        json = await res.json();
    } catch (e) {
        const detail = e instanceof Error ? e.message : String(e);
        throw new CommandExecutionError(
            `Malformed JSON from Stack Exchange API for ${label}: ${detail}`,
            'The API returned a non-JSON body — likely a transient outage',
        );
    }
    if (json && json.error_id) {
        throw new CommandExecutionError(
            `Stack Exchange API error ${json.error_id} (${json.error_name}) for ${label}: ${json.error_message || ''}`,
            'Common causes: invalid filter, throttled, or quota exhausted',
        );
    }
    return json;
}

/**
 * CLI args may arrive as strings (`--limit 5` → `'5'`) when not coerced by the
 * arg type system. Coerce-then-validate so `Number.isInteger` actually catches
 * the bad cases, and reject NaN explicitly.
 */

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the request — it is usually a transient outage or interception
  2. Inspect the raw response: curl -s https://api.stackexchange.com/2.2/questions/<id>?site=stackoverflow | head -c 200 to see what is actually returned
  3. Check whether a proxy/captive portal is intercepting the connection (look for HTML in the body)
  4. Verify TLS is not being MITM'd by VPN/security software; bypass or trust its certificate

Example fix

async function safeFetchJson(url, label) {
  const res = await fetch(url);
  const text = await res.text();
  try {
    return JSON.parse(text);
  } catch (e) {
    throw new Error(`Non-JSON body for ${label}: ${text.slice(0, 120)}`);
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function looksLikeJsonResponse(url) {
  const res = await fetch(url);
  const ct = res.headers.get('content-type') ?? '';
  return ct.includes('application/json');
}
// warn if false before parsing: intercepting proxy or HTML error page likely

Try / catch

try {
  const data = await qData(id);
} catch (e) {
  if (/Malformed JSON from Stack Exchange API/.test(e?.message ?? '')) {
    console.error('Non-JSON body — transient outage or proxy interference. Retrying in 30s...');
    await new Promise(r => setTimeout(r, 30000));
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: res.json() rejects on any caller's response: an HTML error/maintenance page returned with status 200, a proxy or captive portal injecting a login page, truncated/garbled response body, or wrong Content-Type body from an intercepting middlebox.

Common situations: Corporate SSL-inspection proxies replacing the JSON with an HTML warning page; hotel/airport captive portals intercepting HTTPS; Stack Exchange returning a compressed or partial body during brief incidents; local MITM debugging tools breaking the stream.

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/16cb2aea40f4a6ec. Report an issue: GitHub.