jackwener/OpenCLI · error · CommandExecutionError

${label} returned invalid JSON

Error message

${label} returned invalid JSON

What it means

eutilsFetch wraps NCBI E-utilities HTTP calls and parses the JSON body when retmode is JSON. If response.json() throws (and the failure is not already a CommandExecutionError from assertNoEutilsError), it rethrows as `${label} returned invalid JSON` with the parse error as detail. The library throws this because it cannot distinguish an API problem from corrupted/non-JSON output, so it fails loudly instead of returning undefined data.

Source

Thrown at clis/pubmed/utils.js:121

        throw new CommandExecutionError(`${label} request failed`, detail);
    }
    if (!response.ok) {
        throw new CommandExecutionError(`${label} HTTP ${response.status}`, 'Check NCBI availability, request parameters, and optional NCBI_API_KEY.');
    }
    if (retmode === 'xml') {
        return response.text();
    }
    try {
        const json = await response.json();
        assertNoEutilsError(json, label);
        return json;
    }
    catch (error) {
        if (error instanceof CommandExecutionError) {
            throw error;
        }
        const detail = error instanceof Error ? error.message : String(error);
        throw new CommandExecutionError(`${label} returned invalid JSON`, detail);
    }
}

export function assertNoEutilsError(json, label = 'PubMed E-utilities') {
    const error = json?.error
        || json?.esearchresult?.errorlist?.phrasesnotfound?.join(', ')
        || json?.esearchresult?.errorlist?.fieldsnotfound?.join(', ');
    if (error) {
        throw new CommandExecutionError(`${label} returned an error`, String(error));
    }
}

export function buildPubMedUrl(pmid) {
    return `https://pubmed.ncbi.nlm.nih.gov/${pmid}/`;
}

export function decodeXmlEntities(value) {
    return String(value ?? '')

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the call after a short delay; NCBI rate limits (3 req/s without API key) commonly trigger HTML throttle pages
  2. Request a free NCBI_API_KEY and set it to raise the rate limit to 10 req/s
  3. Check NCBI E-utilities status and network path (proxy/VPN) that may inject HTML
  4. Inspect the `detail` field of the CommandExecutionError to see the exact JSON parse failure

Example fix

// before
const json = await esearch(query);
// after
let json;
try {
  json = await esearch(query);
} catch (e) {
  if (/returned invalid JSON/.test(e.message)) {
    await new Promise(r => setTimeout(r, 1000)); // back off, then retry
    json = await esearch(query);
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate the endpoint reachability before parsing
const res = await fetch(url);
const ct = res.headers.get('content-type') || '';
if (!ct.includes('application/json')) throw new Error(`Expected JSON, got ${ct}`);

Type guard

function isJsonObject(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v);
}

Try / catch

try {
  const json = await esearch(query);
} catch (e) {
  if (/returned invalid JSON/.test(e.message)) {
    await backoff(1000);
    return esearch(query); // retry once
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling esearch, esummary/result, or eutilsFetch against an NCBI endpoint whose 200 response body is not valid JSON — e.g. an HTML error/interstitial page, a rate-limit or maintenance page, a proxy/captive portal injecting HTML, or a truncated response.

Common situations: NCBI throttling without an NCBI_API_KEY returning HTML instead of JSON; corporate proxies or VPNs rewriting responses; NCBI service outages; network middleware returning empty bodies with 200 status.

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/4a9a4ae12c1da3cb. Report an issue: GitHub.