jackwener/OpenCLI · warning · CommandExecutionError
${label} returned HTTP 429 (rate limited)
Error message
${label} returned HTTP 429 (rate limited) What it means
steamFetch detects HTTP 429 from Steam and throws a CommandExecutionError indicating the operation was rate limited, advising a short wait. Steam throttles bursty traffic against its store endpoints.
Source
Thrown at clis/steam/utils.js:66
'Copy the numeric id from `steam search` or the URL `store.steampowered.com/app/<id>/`.',
);
}
return s;
}
export async function steamFetch(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 store.steampowered.com is reachable from this network.',
);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'Steam throttles bursty traffic; wait a few seconds and retry.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, 'Steam returned 404 — the resource does not exist.');
}
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
- Wait a few seconds and retry the same command
- Add a delay/backoff between successive Steam requests in batch scripts
- Reduce batch size or spread lookups over time
- Cache results locally to avoid repeat requests for the same id
Example fix
// before
for (const id of ids) await steamFetch(appUrl(id), 'app details'); // bursts trigger 429
// after
for (const id of ids) {
await steamFetch(appUrl(id), 'app details');
await new Promise(r => setTimeout(r, 1000));
} Defensive patterns
Strategy: retry
Validate before calling
// no pre-check possible; mitigate with throttling const sleep = (ms) => new Promise(r => setTimeout(r, ms)); await sleep(1000); // between consecutive steamFetch calls
Type guard
null
Try / catch
try { return await steamFetch(url, label); } catch (e) { if (/429/.test(e.message)) { await sleep(5000); return steamFetch(url, label); } throw e; } Prevention
- Throttle batch requests with delays of at least ~1s
- Cache Steam responses to avoid repeat lookups
- Use exponential backoff on 429
- Avoid shared datacenter IPs when possible
When it happens
Trigger: Hitting store.steampowered.com endpoints repeatedly in a tight loop: batch-fetching many app ids, re-running search commands rapidly, or sharing an IP with other Steam API traffic.
Common situations: Batch scripts iterating hundreds of app ids without delay, CI jobs with frequent Steam lookups, office networks where many users share one egress IP, retry storms after earlier failures.
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}
- Chess.com callback returned HTTP ${resp.status} for ${url}
- Ctrip flight API returned HTTP ${status || 'unknown'}
- dongchedi ${contextHint} HTTP ${resp.status}
- eastmoney convertible failed: HTTP ${resp.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6b1d84e5cf197a39.
Report an issue: GitHub.