{"record":{"id":"224971ea84d6a574","repo":"jackwener/OpenCLI","slug":"coingecko-returned-http-429-rate-limited-224971","errorCode":null,"errorMessage":"coingecko returned HTTP 429 (rate limited)","messagePattern":"coingecko returned HTTP 429 \\(rate limited\\)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":429,"severity":"warning","filePath":"clis/coingecko/coin.js","lineNumber":57,"sourceCode":"        const url = new URL(`https://api.coingecko.com/api/v3/coins/${id}`);\n        url.searchParams.set('localization', 'false');\n        url.searchParams.set('tickers', 'false');\n        url.searchParams.set('market_data', 'true');\n        url.searchParams.set('community_data', 'false');\n        url.searchParams.set('developer_data', 'false');\n        url.searchParams.set('sparkline', 'false');\n\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n        } catch (error) {\n            throw new CommandExecutionError(`coingecko coin request failed: ${error?.message || error}`);\n        }\n        if (resp.status === 404) {\n            throw new EmptyResultError('coingecko coin', `coingecko has no coin with id \"${id}\".`);\n        }\n        if (resp.status === 429) {\n            throw new CommandExecutionError('coingecko returned HTTP 429 (rate limited)', 'Free tier allows ~30 calls/min. Wait and retry.');\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`coingecko coin failed: HTTP ${resp.status}`);\n        }\n        let data;\n        try {\n            data = await resp.json();\n        } catch (error) {\n            throw new CommandExecutionError(`coingecko returned malformed JSON: ${error?.message || error}`);\n        }\n        if (data?.error) {\n            throw new CommandExecutionError(`coingecko returned error: ${data.error}`);\n        }\n\n        const md = data.market_data || {};\n        const pick = (obj, key) => (obj && obj[key] != null ? obj[key] : null);\n        const isoFromMaybe = (s) => (s ? String(s).slice(0, 10) : '');\n        const price = pick(md.current_price, currency);","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/coin.js#L39-L75","documentation":"This CommandExecutionError is thrown when CoinGecko responds with HTTP 429, indicating the client exceeded the public API rate limit. The free/unauthenticated tier allows roughly 30 calls per minute, so bursts of CLI invocations (loops over many coins) commonly trip it. The remediation hint is attached as a second argument.","triggerScenarios":"Calling `coingecko coin` more than ~30 times per minute from a shared IP; scripted loops over many coins; multiple processes/users behind one NAT; the 404/429 branch order means this only fires on a 429 status.","commonSituations":"Batch scripts fetching prices for a portfolio of hundreds of coins without delays; CI jobs hitting the shared public API; other apps on the same network consuming the same rate budget.","solutions":["Wait ~60 seconds and retry with backoff","Add throttling (e.g. 2+ second sleep between calls) when looping over multiple coins","Get a free demo/paid CoinGecko API key and use the pro endpoint for higher limits"],"exampleFix":"// before\nfor (const id of ids) await run(['coingecko', 'coin', id]);\n// after\nfor (const id of ids) { await run(['coingecko', 'coin', id]); await new Promise(r => setTimeout(r, 2500)); }","handlingStrategy":"retry","validationCode":"// throttle before each call in loops\nawait new Promise(r => setTimeout(r, 2500)); // keeps under ~30 calls/min","typeGuard":"null","tryCatchPattern":"try { await run(['coingecko', 'coin', id]); } catch (e) { if (/HTTP 429/.test(e.message)) { await sleep(60000); return retryOnce(); } throw e; }","preventionTips":["Serialize CoinGecko calls with 2-3s delays in scripts","Cache results instead of re-fetching unchanged data","Use a paid/demo API key for higher rate limits"],"tags":["rate-limit","http-429","api-request"],"backgroundTag":"http-429-rate-limited","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}