jackwener/OpenCLI · error · CommandExecutionError

wikipedia returned malformed JSON: ${error?.message || error

Error message

wikipedia returned malformed JSON: ${error?.message || error}

What it means

After a 2xx response, page.js parses the body with resp.json(). If parsing fails — the body is not valid JSON (HTML error/interstitial page, truncated stream, wrong content type) — it throws a CommandExecutionError with the parse error message.

Source

Thrown at clis/wikipedia/page.js:69

        let resp;
        try {
            resp = await fetch(url, {
                headers: {
                    'User-Agent': 'opencli/1.0 (+https://github.com/jackwener/opencli)',
                    'Accept': 'application/json',
                },
            });
        } catch (error) {
            throw new CommandExecutionError(`wikipedia page request failed: ${error?.message || error}`);
        }
        if (!resp.ok) {
            throw new CommandExecutionError(`wikipedia page failed: HTTP ${resp.status}`);
        }
        let data;
        try {
            data = await resp.json();
        } catch (error) {
            throw new CommandExecutionError(`wikipedia returned malformed JSON: ${error?.message || error}`);
        }
        if (data?.error) {
            throw new CommandExecutionError(`wikipedia API error: ${data.error.info || data.error.code}`);
        }
        const pages = Array.isArray(data?.query?.pages) ? data.query.pages : [];
        const page = pages[0];
        if (!page || page.missing) {
            throw new EmptyResultError('wikipedia page', `No article "${title}" on ${lang}.wikipedia.org. Try \`opencli wikipedia search\` first.`);
        }
        const fullExtract = String(page.extract ?? '');
        if (!fullExtract.trim()) {
            throw new EmptyResultError('wikipedia page', `Article "${page.title}" exists but has no plain-text extract (likely a disambiguation/redirect page).`);
        }
        const allParas = fullExtract.split(/\n{2,}/).map(s => s.trim()).filter(Boolean);
        const paras = paragraphsCap > 0 ? allParas.slice(0, paragraphsCap) : allParas;

        return [{
            title: page.title,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Capture and inspect the raw response text to see what was actually returned
  2. Retry — truncation is often transient
  3. Bypass proxies/VPNs or fix captive-portal connectivity
  4. Confirm the request targets <lang>.wikipedia.org/w/api.php with format=json

Example fix

// before
const data = await resp.json();
// after
const text = await resp.text();
let data;
try { data = JSON.parse(text); }
catch { throw new Error(`unexpected body: ${text.slice(0, 200)}`); }
Defensive patterns

Strategy: try-catch

Type guard

function looksLikeApiJson(v) { return v !== null && typeof v === 'object' && ('query' in v || 'error' in v); }

Try / catch

try {
  return await pageCommand(args);
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('malformed JSON')) {
    console.error('non-JSON body from wikipedia — likely proxy/interstitial; retry');
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: A proxy, captive portal, or anti-bot layer returning an HTML page with status 200; the response stream being cut off mid-body; hitting a non-API URL that serves HTML while still reporting success.

Common situations: Corporate networks or hotel Wi-Fi injecting login pages; aggressive caching middleboxes serving stale HTML; malformed responses during partial Wikimedia incidents.

Understand the failure class

Related errors


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