jackwener/OpenCLI · error · CommandExecutionError
coingecko exchanges returned malformed JSON: ${err?.message
Error message
coingecko exchanges returned malformed JSON: ${err?.message ?? err} What it means
The library calls resp.json() on the CoinGecko exchanges response; if the body is not valid JSON (HTML error pages from proxies/Cloudflare, truncated responses, empty bodies), json() throws and this CommandExecutionError wraps that parse failure with the underlying SyntaxError message.
Source
Thrown at clis/coingecko/exchanges.js:58
}
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 ?? ''),
yearEstablished: ex.year_established != null ? Number(ex.year_established) : null,
url: String(ex.url ?? ''),
}));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw body with `curl -s https://api.coingecko.com/api/v3/exchanges?per_page=20&page=1 | head` to see what is actually returned (HTML challenge vs JSON).
- If Cloudflare/proxy HTML is the cause, retry from a different network or use a proper API key plan that avoids challenge pages.
- Retry the request — truncated bodies from flaky connections are usually transient.
- Check for proxies (HTTP_PROXY/HTTPS_PROXY, corporate MITM) interfering with the response encoding.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await exchanges.func({ page: 1 });
} catch (e) {
if (/malformed JSON/.test(e.message)) {
// body was HTML/truncated: verify raw response, retry or switch network
const raw = await fetch('https://api.coingecko.com/api/v3/exchanges?per_page=5&page=1').then(r => r.text());
if (raw.trimStart().startsWith('<')) handleCloudflareChallenge();
} else throw e;
} Prevention
- Spot-check raw responses with curl when behind unfamiliar networks.
- Disable or correctly configure proxies that rewrite HTML into responses.
- Treat JSON parse failures on 2xx as a proxy/Cloudflare symptom, not a code bug.
- Retry truncated responses — they are usually transient.
When it happens
Trigger: The HTTP request succeeded (2xx) but resp.json() throws: response body is HTML (Cloudflare challenge page, captive portal), response is truncated, Content-Encoding mismatch (e.g. broken gzip via a proxy), or an empty body.
Common situations: Corporate proxies injecting HTML login pages, Cloudflare bot-challenge interstitials returned with a 200, flaky mobile/VPN connections truncating the body, or misconfigured local MITM proxies.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- coingecko categories returned malformed JSON: ${err?.message
- DuckDuckGo suggest returned malformed JSON: ${err?.message ?
- ${label} returned malformed JSON: ${err?.message ?? err}
- ${label} returned a non-JSON response
- Bilibili creator comparison returned malformed stat data for
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f4175a3e23f55a93.
Report an issue: GitHub.