jackwener/OpenCLI · error · CommandExecutionError
coingecko returned HTTP 429 (rate limited)
Error message
coingecko returned HTTP 429 (rate limited)
What it means
CoinGecko responded with HTTP 429 and the CLI short-circuits into a CommandExecutionError with guidance. The free tier of the CoinGecko public API is rate limited (~30 calls/min).
Source
Thrown at clis/coingecko/categories.js:47
);
}
const limit = Number(args.limit ?? 20);
if (!Number.isInteger(limit) || limit <= 0) {
throw new ArgumentError('coingecko limit must be a positive integer');
}
if (limit > 100) {
throw new ArgumentError('coingecko limit must be <= 100');
}
const url = `https://api.coingecko.com/api/v3/coins/categories?order=${encodeURIComponent(sort)}`;
let resp;
try {
resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
}
catch (err) {
throw new CommandExecutionError(`coingecko categories request failed: ${err?.message ?? err}`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
'coingecko returned HTTP 429 (rate limited)',
'Free tier allows ~30 calls/min. Wait and retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`coingecko categories returned HTTP ${resp.status}`);
}
let data;
try {
data = await resp.json();
}
catch (err) {
throw new CommandExecutionError(`coingecko categories returned malformed JSON: ${err?.message ?? err}`);
}
if (!Array.isArray(data) || !data.length) {
throw new EmptyResultError('coingecko categories', 'CoinGecko returned no category data.');
}
return data.slice(0, limit).map((cat, i) => ({View on GitHub (pinned to 49907e53dc)
Solutions
- Wait a minute and retry with backoff
- Add throttling/delay between calls (<=30 req/min)
- Move to a CoinGecko paid/demo API plan with a key and higher limits
Example fix
// before
for (const s of sorts) await run(`categories.js --sort ${s}`);
// after
for (const s of sorts) {
await run(`categories.js --sort ${s}`);
await sleep(2500); // stay under ~30 req/min
} Defensive patterns
Strategy: retry
Validate before calling
// client-side throttle: max ~30 req/min
let lastCall = 0;
async function throttled(fn, minGapMs = 2100) {
const wait = lastCall + minGapMs - Date.now();
if (wait > 0) await sleep(wait);
lastCall = Date.now();
return fn();
} Type guard
function isRateLimited(err) {
return err instanceof CommandExecutionError && /HTTP 429|rate limited/i.test(err.message);
} Try / catch
try {
await throttled(() => runCategories(args));
} catch (err) {
if (isRateLimited(err)) {
await sleep(60_000);
return runCategories(args);
}
throw err;
} Prevention
- Serialize CoinGecko calls with a >=2s gap
- Use an API key / paid plan for higher rate limits
- Cache category results instead of re-fetching repeatedly
When it happens
Trigger: Calling the categories command more than ~30 times per minute from one IP, or sharing an IP with other CoinGecko API consumers.
Common situations: Loops/scripts hammering CoinGecko without delays; shared CI runner IPs already rate limited; multiple team members polling from the same egress IP.
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)
- ${label} returned HTTP 429 (rate limited)
- archive snapshots failed: HTTP ${resp.status}
- autohome ${contextHint} HTTP ${resp.status}
- coingecko categories request failed: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7b39549d6079ae3c.
Report an issue: GitHub.