jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${resp.status}
Error message
${label} returned HTTP ${resp.status} What it means
lichessFetch wraps all Lichess API calls and throws CommandExecutionError when the HTTP response status is not ok. The 429 rate-limit case is handled separately with a richer message; this generic branch covers every other non-2xx status (404, 403, 5xx, etc.). It signals the Lichess endpoint rejected the request for a reason other than rate limiting.
Source
Thrown at clis/lichess/utils.js:79
resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that lichess.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `Lichess returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'Lichess throttles anonymous traffic at ~60 req/min; back off and retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
}
let body;
try {
body = await resp.json();
}
catch (err) {
throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
}
return body;
}
/** Format a lichess unix-ms timestamp as ISO date (YYYY-MM-DD). `null` when missing. */
export function formatTimestamp(ms) {
if (typeof ms !== 'number' || !Number.isFinite(ms) || ms <= 0) return null;
const d = new Date(ms);
if (Number.isNaN(d.getTime())) return null;
return d.toISOString();
}View on GitHub (pinned to 49907e53dc)
Solutions
- Read resp.status in the error context and check Lichess API docs for that code (404 = not found, 403 = forbidden, 5xx = server side).
- Verify the username/ID/endpoint path passed to the command is correct.
- Check https://status.lichess.org for outages if the status is 5xx.
- Retry later if transient; if 403, obtain an OAuth token if the endpoint requires one.
Example fix
// before
const games = await lichessFetch('/api/user/definitely-not-a-user');
// after
let games;
try {
games = await lichessFetch('/api/user/existing-user');
} catch (e) {
if (String(e.message).includes('HTTP 404')) throw new EmptyResultError('no such lichess user');
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const m = /^lichess\b/i.test(cmd) && /\S+/.test(args[0] || '') ? args[0] : null;
if (!m) throw new Error('supply a valid lichess username/endpoint argument'); Type guard
function isOkStatus(status) { return Number.isInteger(status) && status >= 200 && status < 300; } Try / catch
try {
const data = await lichessFetch(path);
} catch (e) {
const m = /HTTP (\d{3})/.exec(e.message);
if (m) {
const status = Number(m[1]);
if (status >= 500 || status === 429) { /* retry with backoff */ }
else throw new Error(`lichess request failed: ${status}`);
} else throw e;
} Prevention
- Validate usernames/IDs against known patterns before calling.
- Check https://status.lichess.org before blaming your code on 5xx.
- Use an OAuth token for endpoints that require authentication.
- Distinguish 4xx (fix your input) from 5xx (retry later) in handling code.
When it happens
Trigger: Any lichessFetch call (via body and the lichess subcommands) where resp.ok is false and status !== 429 — e.g. requesting a non-existent user (404), hitting an endpoint that requires OAuth (403), or Lichess returning 5xx during incidents.
Common situations: Typing a wrong username in a lichess command; Lichess API outage or maintenance; calling an endpoint that now requires authentication after a Lichess API change; proxy/firewall injecting error responses.
Related errors
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- HTTP ${result.httpStatus} from /api/organizations
- ${label} returned HTTP ${res.status}
- HTTP_ERROR
- HTTP_ERROR
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6dac3cd47ed12784.
Report an issue: GitHub.