jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP 429 (rate limited)
Error message
${label} returned HTTP 429 (rate limited) What it means
Wikidata rate-limits anonymous (keyless) traffic. When the endpoint answers HTTP 429, wikidataFetch raises a CommandExecutionError advising the caller to back off and retry. This is a deliberate retryable-failure signal, not a bug in your code.
Source
Thrown at clis/wikidata/utils.js:76
return raw;
}
export async function wikidataFetch(url, label) {
let resp;
try {
resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that www.wikidata.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `Wikidata returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'Wikidata throttles anonymous traffic; 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;
}
/**View on GitHub (pinned to 49907e53dc)
Solutions
- Add a delay/backoff between requests and retry after waiting (respect Retry-After if present)
- Cache responses so the same entity is not fetched repeatedly
- Reduce batch size or split the work across a longer window
- Apply for a Bot username/API agreement with Wikidata for higher limits
Example fix
// before
for (const qid of qids) results.push(await fetchEntity(qid));
// after
for (const qid of qids) {
results.push(await fetchEntity(qid));
await new Promise(r => setTimeout(r, 500)); // stay under anonymous rate limit
} Defensive patterns
Strategy: retry
Validate before calling
if (pendingRequests > 50) await new Promise(r => setTimeout(r, 1000)); // self-throttle before calling
Try / catch
const fetchWithRetry = async (url, label, retries = 3) => {
for (let i = 0; ; i++) {
try { return await wikidataFetch(url, label); }
catch (err) {
if (!String(err.message).includes('429') || i >= retries) throw err;
await new Promise(r => setTimeout(r, 1000 * 2 ** i));
}
}
}; Prevention
- Throttle anonymous requests (e.g. >=200-500ms between calls)
- Cache entity lookups to avoid repeat fetches
- Implement exponential backoff on 429
- Prefer batched wbgetentities calls over per-ID requests
When it happens
Trigger: Sending many wikidataFetch calls in a tight loop (e.g. fetching hundreds of Q-IDs sequentially without delay) so anonymous requests to www.wikidata.org exceed the per-IP quota; shared/proxy IPs already exhausted by other traffic.
Common situations: Batch scripts iterating over large entity lists; CI runners making repeated lookups from datacenter IPs with shared quotas; re-running a failed pipeline immediately after a 429.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- coingecko returned HTTP 429 (rate limited)
- archive snapshots failed: HTTP ${resp.status}
- autohome ${contextHint} HTTP ${resp.status}
- coingecko returned HTTP 429 (rate limited)
- coingecko derivatives returned HTTP 429 (rate limited)
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6ecf6f3fb5162503.
Report an issue: GitHub.