jackwener/OpenCLI · error · CommandExecutionError

coingecko exchanges returned HTTP ${resp.status}

Error message

coingecko exchanges returned HTTP ${resp.status}

What it means

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).

Source

Thrown at clis/coingecko/exchanges.js:51

        }
        const url = new URL('https://api.coingecko.com/api/v3/exchanges');
        url.searchParams.set('per_page', String(limit));
        url.searchParams.set('page', String(page));
        let resp;
        try {
            resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
        }
        catch (err) {
            throw new CommandExecutionError(`coingecko exchanges request failed: ${err?.message ?? err}`);
        }
        if (resp.status === 429) {
            throw new CommandExecutionError(
                'coingecko returned HTTP 429 (rate limited)',
                'Free tier allows ~30 calls/min. Wait and retry.',
            );
        }
        if (!resp.ok) {
            throw new CommandExecutionError(`coingecko exchanges returned HTTP ${resp.status}`);
        }
        let data;
        try {
            data = await resp.json();
        }
        catch (err) {
            throw new CommandExecutionError(`coingecko exchanges returned malformed JSON: ${err?.message ?? err}`);
        }
        if (!Array.isArray(data) || !data.length) {
            throw new EmptyResultError('coingecko exchanges', 'CoinGecko returned no exchange data.');
        }
        return data.map((ex, i) => ({
            rank: (page - 1) * limit + i + 1,
            id: String(ex.id ?? ''),
            name: String(ex.name ?? ''),
            trustScore: ex.trust_score != null ? Number(ex.trust_score) : null,
            volume24hBtc: ex.trade_volume_24h_btc != null ? Number(ex.trade_volume_24h_btc) : null,
            country: String(ex.country ?? ''),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the status code in the message: 5xx means CoinGecko-side — retry later with backoff; 4xx means the request itself needs fixing.
  2. Check the CoinGecko status page or status.twitter/X for ongoing incidents.
  3. Retry transient 5xx with exponential backoff; do not retry 4xx blindly.
  4. If 403 persists, your IP may be blocked — try from a different network or add a valid API key/plan.

Example fix

// before
try { await exchanges.func({ page: 1 }); } catch (e) { throw e; }
// after
try {
  await exchanges.func({ page: 1 });
} catch (e) {
  if (/HTTP 5\d\d/.test(e.message)) await retryWithBackoff(() => exchanges.func({ page: 1 }));
  else throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await exchanges.func({ page: 1 });
} catch (e) {
  const m = e.message.match(/HTTP (\d{3})/);
  if (m && m[1] >= 500) retryLater();       // server-side: backoff + retry
  else if (m && m[1] === 403) switchNetworkOrUseApiKey();
  else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: CoinGecko incidents (check status.coinantica/gecko status page), Cloudflare bot-protection blocking datacenter IPs, or transient 5xx during high load.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/25d8a7f7ef0fec68. Report an issue: GitHub.