jackwener/OpenCLI · error · CommandExecutionError

stack exchange HTTP ${resp.status}: ${body || resp.statusTex

Error message

stack exchange HTTP ${resp.status}: ${body || resp.statusText}

What it means

CommandExecutionError thrown by seFetch for any non-OK HTTP status other than 429. It attempts to parse the response JSON and surface the API's `error_message`; if that fails it falls back to the HTTP statusText. Typical statuses: 400 (bad parameter), 404 (bad path/id), 503 (SE maintenance).

Source

Thrown at clis/stackoverflow/utils.js:68

    let resp;
    try {
        resp = await fetch(url, {
            headers: {
                'Accept': 'application/json',
                'Accept-Encoding': 'gzip',
                'User-Agent': UA,
            },
        });
    } catch (error) {
        throw new CommandExecutionError(`stack exchange request failed: ${error?.message || error}`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError('stack exchange returned HTTP 429 (rate limited)', 'Wait a few seconds and retry, or lower --limit.');
    }
    if (!resp.ok) {
        let body = '';
        try { body = (await resp.json())?.error_message || ''; } catch { /* ignore */ }
        throw new CommandExecutionError(`stack exchange HTTP ${resp.status}: ${body || resp.statusText}`);
    }
    let data;
    try {
        data = await resp.json();
    } catch (error) {
        throw new CommandExecutionError(`stack exchange returned malformed JSON: ${error?.message || error}`);
    }
    if (data?.error_id) {
        throw new CommandExecutionError(
            `stack exchange API error: ${data.error_message || data.error_name}`,
            'Inspect the URL in a browser for the canonical error context.',
        );
    }
    return data;
}

/** Convert SE epoch seconds to YYYY-MM-DD. */
export function epochToDate(value) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the embedded error_message in the thrown message — SE error bodies usually state the exact bad parameter.
  2. Retry later on 5xx; check https://www.stackstatus.com for outages.
  3. Ensure ids are encodeURIComponent'd and paths match the 2.3 API (see utils.js SE_API).
  4. If a proxy intercepts (statusText like 'Forbidden' with no error_message), bypass or reconfigure the proxy.

Example fix

// before: assuming any failure is transient
await seFetch(path);
// after
catch (e) {
  const m = /stack exchange HTTP (\d+)/.exec(e.message);
  if (m && Number(m[1]) >= 500) return retryWithBackoff(path);
  throw e; // 4xx: fix the request
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate before calling: ids numeric, paths encoded
if (!/^\/questions\/[\d;]+$/.test(path)) throw new TypeError(`unexpected SE path: ${path}`);

Try / catch

try {
  return await seFetch(path);
} catch (e) {
  const m = /stack exchange HTTP (\d+)/.exec(String(e.message));
  if (m) {
    const status = Number(m[1]);
    if (status >= 500) return retryWithBackoff(path);           // transient SE-side
    console.error(`SE rejected the request (${status}): ${e.message}`); // 4xx: fix input
    process.exitCode = 2;
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Malformed API request producing SE error 400 (e.g. invalid sort/pagesize combination); requesting a path that doesn't exist (404); Stack Exchange returning 500/503 during incidents or maintenance windows.

Common situations: Stack Exchange API incidents (status.stackoverflow.com); hand-constructed paths with unencoded characters; version drift if SE changes endpoint requirements; intermediary proxies returning HTML error pages (then error_message is empty and only statusText shows).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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