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
- Retry the request after a delay, honoring backoff if status was 429
- Check https://www.lesswrong.com status / try the query in a browser to confirm the service is up
- Reduce request frequency or batch queries to avoid rate limits
- 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
- Add exponential backoff with retry on 429/5xx
- Space out LessWrong queries to avoid rate limits
- Monitor lesswrong.com status before bulk runs
- Avoid suspicious IPs/VPNs that trigger Cloudflare 403
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
- Could not fetch lists: ${listsData.__error}
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
- 1point3acres request failed: HTTP ${res.status} ${res.status
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3b2101d846d97e82.
Report an issue: GitHub.