jackwener/OpenCLI · warning · CommandExecutionError
${label} returned HTTP 429 (rate limited)
Error message
${label} returned HTTP 429 (rate limited) What it means
restCountriesFetch throws CommandExecutionError when the REST Countries API responds with HTTP 429, meaning the client exceeded the service's rate limit. The library surfaces the 429 as a distinct, explicitly-named 'rate limited' error so callers know the failure is temporary and quota-related, not a bad query or outage.
Source
Thrown at clis/rest-countries/utils.js:67
return raw;
}
export async function restCountriesFetch(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 restcountries.com is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `REST Countries returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(`${label} returned HTTP 429 (rate limited)`);
}
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;
}
/** Convert REST Countries' `{cur: {name, symbol}}` map to a comma-joined list. */
export function joinCurrencies(currencies) {
if (!currencies || typeof currencies !== 'object') return '';
return Object.entries(currencies)View on GitHub (pinned to 49907e53dc)
Solutions
- Wait (e.g. 30-60 seconds) and retry the same command, ideally with backoff
- Add a delay between consecutive rest-countries calls in batch scripts
- Cache previously fetched country data locally to reduce repeat API calls
- Check whether a shared proxy/VPN IP is causing the throttling and use a different egress
Example fix
// before
for (const c of ['france','germany','spain']) await getCountry(c);
// after
for (const c of ['france','germany','spain']) {
await getCountry(c);
await new Promise(r => setTimeout(r, 1500)); // stay under rate limit
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
try {
await restCountriesCommand(args);
} catch (e) {
if (String(e.message).includes('429')) {
await sleep(60000); // backoff, then retry once
return await restCountriesCommand(args);
}
throw e;
} Prevention
- Throttle batch lookups with an inter-request delay (1-2s)
- Cache country data locally; country facts rarely change
- Avoid parallel requests to restcountries.com
- Watch for 429 in logs and back off exponentially
When it happens
Trigger: Calling any rest-countries command (which internally calls restCountriesFetch) repeatedly in a short window, or sharing an IP/proxy with other heavy users of restcountries.com, until the API throttles the request with a 429 response.
Common situations: Batch scripts iterating over many country lookups without delay; CI jobs making parallel requests; shared corporate/VPN egress IP already rate-limited by REST Countries' free-tier quota.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- autohome ${contextHint} HTTP ${resp.status}
- Ctrip flight API returned HTTP ${status || 'unknown'}
- dongchedi ${contextHint} HTTP ${resp.status}
- eastmoney convertible failed: HTTP ${resp.status}
- HTTP_ERROR
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2875579fdbef218e.
Report an issue: GitHub.