jackwener/OpenCLI · warning · CommandExecutionError
${label} returned HTTP 429 (rate limited)
Error message
${label} returned HTTP 429 (rate limited) What it means
flathubFetch throws CommandExecutionError '<label> returned HTTP 429 (rate limited)' when flathub.org responds with 429, meaning the client exceeded Flathub's request rate limits. The library raises it as a distinct error so callers can recognize throttling and back off rather than hammering the API.
Source
Thrown at clis/flathub/utils.js:66
let resp;
try {
resp = await fetch(url, {
method: init?.method ?? 'GET',
headers: { 'user-agent': UA, accept: 'application/json', ...(init?.headers ?? {}) },
body: init?.body,
});
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that flathub.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `Flathub 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;
}
export function joinList(value, max = 10) {
if (!Array.isArray(value)) return '';
const items = value.filter((v) => typeof v === 'string' && v.trim());
if (items.length === 0) return '';View on GitHub (pinned to 49907e53dc)
Solutions
- Add a delay between requests (e.g. 1-2s sleep) or implement exponential backoff on 429
- Batch or deduplicate requests — cache appstream results locally instead of refetching
- Reduce concurrency: run requests sequentially or with a small parallelism cap
- Wait and retry later if a shared IP is being throttled
Example fix
// before
for (const id of ids) await appInfo(id); // hammers the API
// after
for (const id of ids) {
await appInfo(id);
await new Promise((r) => setTimeout(r, 1000));
} Defensive patterns
Strategy: retry
Validate before calling
// Throttle before calling: at most 1 request per second const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); await sleep(1000); // between flathub calls in a loop
Type guard
null
Try / catch
async function withBackoff(fn, attempts = 4) {
for (let i = 0; i < attempts; i++) {
try { return await fn(); }
catch (err) {
if (!/HTTP 429/.test(err.message) || i === attempts - 1) throw err;
await new Promise((r) => setTimeout(r, 2 ** i * 1000));
}
}
} Prevention
- Serialize flathub requests with a delay instead of firing them in parallel
- Cache appstream responses locally to avoid refetching the same app
- Avoid tight retry loops without backoff — they worsen rate limiting
- Account for shared IPs (CI runners, office NAT) that may already be throttled
When it happens
Trigger: Looping over many appIds calling the appstream endpoint in rapid succession; concurrent parallel requests from scripts/CI; retry loops without backoff after earlier failures; shared IP (CI runner, corporate NAT) already rate-limited.
Common situations: Batch scripts fetching metadata for hundreds of apps; automated CI jobs polling Flathub; multiple teammates behind one NAT IP; aggressive retry logic after network errors.
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/76193cdadc230d8a.
Report an issue: GitHub.