jackwener/OpenCLI · error · CommandExecutionError

LessWrong API returned HTTP ${resp.status}

Error message

LessWrong API returned HTTP ${resp.status}

What it means

gqlRequest calls the LessWrong GraphQL HTTP endpoint and requires a 2xx response. Any non-OK HTTP status (403, 429, 5xx, etc.) throws CommandExecutionError with the status code. It surfaces transport-level failures before GraphQL error handling.

Source

Thrown at clis/lesswrong/_helpers.js:17

import { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
export const SITE = 'lesswrong';
export const DOMAIN = 'www.lesswrong.com';
const GRAPHQL_URL = `https://${DOMAIN}/graphql`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- GraphQL responses vary per query
export async function gqlRequest(query) {
    const resp = await fetch(GRAPHQL_URL, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
        },
        body: JSON.stringify({ query }),
        signal: AbortSignal.timeout(15000),
    });
    if (!resp.ok) {
        throw new CommandExecutionError(`LessWrong API returned HTTP ${resp.status}`);
    }
    const json = (await resp.json());
    if (json.errors?.length) {
        throw new CommandExecutionError(json.errors[0]?.message ?? 'Unknown GraphQL error');
    }
    return json.data;
}
export function gqlEscape(str) {
    return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
export function stripHtml(html) {
    if (!html)
        return '';
    return html
        .replace(/<script[^>]*>.*?<\/script>/gis, ' ')
        .replace(/<style[^>]*>.*?<\/style>/gis, ' ')
        .replace(/<[^>]+>/g, ' ')
        .replace(/\s+/g, ' ')

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the request after a delay, honoring backoff if status was 429
  2. Check https://www.lesswrong.com status / try the query in a browser to confirm the service is up
  3. Reduce request frequency or batch queries to avoid rate limits
  4. Verify network path (proxy/VPN) is not causing Cloudflare 403 blocks

Example fix

// before
const data = await gqlRequest(query);
// after
const data = await withRetry(() => gqlRequest(query), { retries: 3, backoffMs: 1000 });
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight
const ping = await fetch('https://www.lesswrong.com', { method: 'HEAD' });
if (!ping.ok) console.warn('LessWrong unreachable, expect HTTP errors');

Try / catch

try {
  const data = await gqlRequest(query);
} catch (e) {
  const m = /HTTP (\d+)/.exec(String(e.message));
  if (m) {
    const status = Number(m[1]);
    if (status === 429 || status >= 500) await sleep(backoff); /* retry */
  } else throw e;
}

Prevention

When it happens

Trigger: LessWrong returns HTTP 4xx/5xx for the POSTed GraphQL query: rate limiting (429), Cloudflare block (403), server error (500/502/503), or a malformed request causing 400.

Common situations: Hammering the API with many rapid queries triggers rate limiting; corporate proxy or VPN blocked by Cloudflare; LessWrong downtime during deploys; query too large or malformed leading to 400.

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/3b2101d846d97e82. Report an issue: GitHub.