jackwener/OpenCLI · error · CommandExecutionError
coingecko returned an unexpected response
Error message
coingecko returned an unexpected response
What it means
This CommandExecutionError is thrown when the response parses as JSON, has no error field, but is not an array — /coins/markets must return a JSON array of coin objects. The library guards against unexpected shapes (object, string, null) before mapping columns. It indicates a schema mismatch or interception by something returning its own JSON.
Source
Thrown at clis/coingecko/top.js:49
url.searchParams.set('per_page', String(limit));
url.searchParams.set('page', '1');
url.searchParams.set('sparkline', 'false');
let resp;
try {
resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
} catch (error) {
throw new CommandExecutionError(`coingecko top request failed: ${error?.message || error}`);
}
if (!resp.ok) throw new CommandExecutionError(`coingecko top failed: HTTP ${resp.status}`);
let data;
try {
data = await resp.json();
} catch (error) {
throw new CommandExecutionError(`coingecko returned malformed JSON: ${error?.message || error}`);
}
if (data?.error) throw new CommandExecutionError(`coingecko returned error: ${data.error}`);
if (!Array.isArray(data)) throw new CommandExecutionError('coingecko returned an unexpected response');
if (data.length === 0) throw new EmptyResultError('coingecko top', 'coingecko returned no market data');
return data.map((c) => ({
rank: c.market_cap_rank,
symbol: String(c.symbol ?? '').toUpperCase(),
name: c.name,
price: c.current_price,
change24hPct: c.price_change_percentage_24h,
marketCap: c.market_cap,
volume24h: c.total_volume,
high24h: c.high_24h,
low24h: c.low_24h,
}));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- curl the endpoint and compare the actual JSON shape with the expected array of coin objects.
- Confirm you are hitting api.coingecko.com/api/v3/coins/markets and not a redirected/intercepted URL.
- Check the CoinGecko changelog for /coins/markets schema changes and update the library.
- Bypass proxies/VPN/ad-blockers that could substitute their own JSON responses.
- Retry later if it is a transient CDN incident.
Example fix
// caller: defensive shape check on results
// before
const rows = await runCli('coingecko', 'top');
console.log(rows[0].price);
// after
const rows = await runCli('coingecko', 'top');
if (!Array.isArray(rows) || rows.length === 0) throw new Error('unexpected coingecko output');
console.log(rows[0].price); Defensive patterns
Strategy: type-guard
Validate before calling
const probe = await fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&per_page=1');
const probeBody = await probe.json();
if (!Array.isArray(probeBody)) throw new Error('unexpected /coins/markets shape: ' + JSON.stringify(probeBody).slice(0, 200)); Type guard
function isCoinArray(d) { return Array.isArray(d) && d.every(c => c && typeof c === 'object' && 'id' in c && 'current_price' in c); } Try / catch
try {
rows = await runCli('coingecko', 'top');
} catch (e) {
if (/unexpected response/.test(e.message)) {
console.error('Response shape drifted — check CoinGecko changelog / intercepting proxies');
}
throw e;
} Prevention
- Add a contract test asserting the array shape of /coins/markets
- Bypass proxies/ad-blockers/security appliances for API calls
- Pin the library to versions matching the current API schema
- Check status.coingecko.com when shapes suddenly change
When it happens
Trigger: API returning {data:[...]} after a schema change; a proxy or captive portal returning its own JSON error object; CoinGecko returning a JSON status object on soft failures; accidentally hitting a different endpoint/version.
Common situations: Major API version bumps altering the response envelope; middleboxes (proxies, ad-blockers, security appliances) substituting JSON; CDN error JSON with 200 status; mocking layers returning wrong shapes in tests.
Related errors
- coingecko global returned no data envelope
- coingecko returned malformed JSON: ${error?.message || error
- dblp author search for "${name}" returned a hit without a PI
- Instagram returned non-ok status: ${JSON.stringify(d).slice(
- LinkedIn Learning courses lookup returned malformed payload:
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/25dcb695bbeff811.
Report an issue: GitHub.