jackwener/OpenCLI · warning · CommandExecutionError
${label} returned HTTP 429 (rate limited)
Error message
${label} returned HTTP 429 (rate limited) What it means
CommandExecutionError thrown by dblpFetch when dblp.org responds with HTTP 429 Too Many Requests. dblp rate-limits clients that issue requests too quickly; the library surfaces this explicitly with guidance because 429 is common and recoverable.
Source
Thrown at clis/dblp/utils.js:45
* Wraps `fetch` with typed errors. We always set a UA per dblp's
* polite-fetch guidance (https://dblp.org/faq/How+to+use+the+dblp+search+API.html).
*/
async function dblpFetch(url, label, accept) {
let res;
try {
res = await fetch(url, {
headers: {
accept,
'user-agent': 'opencli-dblp/1.0 (+https://github.com/jackwener/opencli)',
},
});
}
catch (err) {
throw new CommandExecutionError(`${label} request failed: ${err?.message ?? err}`, 'Check that dblp.org is reachable from this network.');
}
if (!res.ok) {
if (res.status === 429) {
throw new CommandExecutionError(`${label} returned HTTP 429 (rate limited)`, 'dblp throttles clients that fetch too aggressively. Wait a few seconds and retry, or lower --limit.');
}
if (res.status === 404) {
throw new EmptyResultError(label, 'dblp returned 404 — the requested record may not exist.');
}
throw new CommandExecutionError(`${label} returned HTTP ${res.status}`, 'Inspect the response in a browser at the same URL for more context.');
}
return res;
}
export async function dblpFetchJson(path, label) {
const res = await dblpFetch(`${DBLP_ORIGIN}${path}`, label, 'application/json');
let body;
try {
body = await res.json();
}
catch (err) {
throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Wait a few seconds and retry — 429 is temporary
- Lower --limit or reduce request frequency; add a sleep between calls
- Serialize requests instead of running them in parallel
- Cache results locally to avoid refetching the same records
- If in CI, add backoff/jitter or route through a less-throttled network
Example fix
// before
for (const name of names) { await run(`dblp author --name ${name}`); }
// Error: dblp author search returned HTTP 429 (rate limited)
// after
for (const name of names) {
await run(`dblp author --name ${name}`);
await new Promise(r => setTimeout(r, 2000));
} Defensive patterns
Strategy: retry
Validate before calling
// Throttle proactively so 429 never happens.
const limiter = pLimit(1); // serialize dblp calls
const throttled = (fn) => (...a) => limiter(async () => {
await sleep(1500);
return fn(...a);
}); Try / catch
async function withBackoff(fn, tries = 4) {
for (let i = 0; i < tries; i++) {
try { return await fn(); }
catch (err) {
if (/HTTP 429/.test(err.message) && i < tries - 1) {
await sleep(2 ** i * 1000);
continue;
}
throw err;
}
}
} Prevention
- Space out dblp requests (≥1–2s) in scripts and CI
- Never fire parallel requests at dblp from one IP
- Cache fetched records to avoid repeat lookups
- Honor a global rate limiter shared across all dblp calls
When it happens
Trigger: Any dblp subcommand executed repeatedly in quick succession — e.g. scripting many `dblp author`/`dblp paper` calls in a tight loop without delay, possibly shared across users behind one IP (CI runners, NAT).
Common situations: Batch scripts iterating over many authors/papers; parallel CI jobs hammering dblp from one IP; shared office/campus IP already throttled; aggressive retry loops.
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)
- coingecko returned HTTP 429 (rate limited)
- coingecko derivatives returned HTTP 429 (rate limited)
- coingecko returned HTTP 429 (rate limited)
- coingecko returned HTTP 429 (rate limited)
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5e0c90b053559e0e.
Report an issue: GitHub.