{"record":{"id":"25d8a7f7ef0fec68","repo":"jackwener/OpenCLI","slug":"coingecko-exchanges-returned-http-resp-status","errorCode":null,"errorMessage":"coingecko exchanges returned HTTP ${resp.status}","messagePattern":"coingecko exchanges returned HTTP (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/exchanges.js","lineNumber":51,"sourceCode":"        }\n        const url = new URL('https://api.coingecko.com/api/v3/exchanges');\n        url.searchParams.set('per_page', String(limit));\n        url.searchParams.set('page', String(page));\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n        }\n        catch (err) {\n            throw new CommandExecutionError(`coingecko exchanges request failed: ${err?.message ?? err}`);\n        }\n        if (resp.status === 429) {\n            throw new CommandExecutionError(\n                'coingecko returned HTTP 429 (rate limited)',\n                'Free tier allows ~30 calls/min. Wait and retry.',\n            );\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`coingecko exchanges returned HTTP ${resp.status}`);\n        }\n        let data;\n        try {\n            data = await resp.json();\n        }\n        catch (err) {\n            throw new CommandExecutionError(`coingecko exchanges returned malformed JSON: ${err?.message ?? err}`);\n        }\n        if (!Array.isArray(data) || !data.length) {\n            throw new EmptyResultError('coingecko exchanges', 'CoinGecko returned no exchange data.');\n        }\n        return data.map((ex, i) => ({\n            rank: (page - 1) * limit + i + 1,\n            id: String(ex.id ?? ''),\n            name: String(ex.name ?? ''),\n            trustScore: ex.trust_score != null ? Number(ex.trust_score) : null,\n            volume24hBtc: ex.trade_volume_24h_btc != null ? Number(ex.trade_volume_24h_btc) : null,\n            country: String(ex.country ?? ''),","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/exchanges.js#L33-L69","documentation":"CoinGecko returned a non-2xx status other than 429 and the library surfaces it as a CommandExecutionError containing the raw status code. This covers server-side rejections like 400/404 (bad query params), 401/403 (blocked or auth issues), and 5xx (CoinGecko outage).","triggerScenarios":"Any resp.ok === false with status != 429 on /api/v3/exchanges: CoinGecko returning 5xx during an outage, a 400 from a malformed request, or a 401/403 if the client IP is blocked by Cloudflare protection.","commonSituations":"CoinGecko incidents (check status.coinantica/gecko status page), Cloudflare bot-protection blocking datacenter IPs, or transient 5xx during high load.","solutions":["Read the status code in the message: 5xx means CoinGecko-side — retry later with backoff; 4xx means the request itself needs fixing.","Check the CoinGecko status page or status.twitter/X for ongoing incidents.","Retry transient 5xx with exponential backoff; do not retry 4xx blindly.","If 403 persists, your IP may be blocked — try from a different network or add a valid API key/plan."],"exampleFix":"// before\ntry { await exchanges.func({ page: 1 }); } catch (e) { throw e; }\n// after\ntry {\n  await exchanges.func({ page: 1 });\n} catch (e) {\n  if (/HTTP 5\\d\\d/.test(e.message)) await retryWithBackoff(() => exchanges.func({ page: 1 }));\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await exchanges.func({ page: 1 });\n} catch (e) {\n  const m = e.message.match(/HTTP (\\d{3})/);\n  if (m && m[1] >= 500) retryLater();       // server-side: backoff + retry\n  else if (m && m[1] === 403) switchNetworkOrUseApiKey();\n  else throw e;\n}","preventionTips":["Distinguish 5xx (retryable) from 4xx (fix request) before retrying.","Watch the CoinGecko status page for incidents in monitoring setups.","Cap retries to avoid hammering a struggling upstream.","If 403 recurs, your IP is likely blocked — use a different network or authenticated plan."],"tags":["http-error","upstream-api","coingecko"],"backgroundTag":"http-error-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}