{"record":{"id":"3ba4b8edd5668197","repo":"jackwener/OpenCLI","slug":"coingecko-global-returned-malformed-json-err-m","errorCode":null,"errorMessage":"coingecko global returned malformed JSON: ${err?.message ?? err}","messagePattern":"coingecko global returned malformed JSON: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/global.js","lineNumber":44,"sourceCode":"        }\n        catch (err) {\n            throw new CommandExecutionError(`coingecko global 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 global returned HTTP ${resp.status}`);\n        }\n        let body;\n        try {\n            body = await resp.json();\n        }\n        catch (err) {\n            throw new CommandExecutionError(`coingecko global returned malformed JSON: ${err?.message ?? err}`);\n        }\n        const data = body?.data;\n        if (!data) {\n            throw new CommandExecutionError('coingecko global returned no data envelope');\n        }\n        const totalMarketCap = data?.total_market_cap?.[currency];\n        const totalVolume = data?.total_volume?.[currency];\n        if (totalMarketCap == null && totalVolume == null) {\n            throw new ArgumentError(\n                `coingecko has no market totals for currency \"${currency}\"`,\n                'Use a CoinGecko-supported quote currency such as usd, cny, eur, or jpy.',\n            );\n        }\n        return [{\n            currency: currency.toUpperCase(),\n            totalMarketCap: totalMarketCap != null ? Number(totalMarketCap) : null,\n            totalVolume24h: totalVolume != null ? Number(totalVolume) : null,\n            marketCapChange24hPct: data.market_cap_change_percentage_24h_usd != null ? Number(data.market_cap_change_percentage_24h_usd) : null,","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/global.js#L26-L62","documentation":"This CommandExecutionError is thrown when the CoinGecko /global endpoint returns an HTTP 200 response whose body cannot be parsed as JSON. The library wraps resp.json() in try/catch and rethrows with the underlying parse message. It signals an API-level response corruption problem, not a user input problem.","triggerScenarios":"fetch succeeded (resp.ok) but resp.json() throws: the endpoint returned HTML instead of JSON (e.g. Cloudflare challenge page), a truncated/garbled body, or a proxy/gateway intercepted the response.","commonSituations":"CoinGecko or Cloudflare serving a bot-challenge HTML page with 200 status; corporate proxies or firewalls rewriting responses; transient network interruption truncating the body; CoinGecko maintenance returning an HTML error page.","solutions":["Retry the command after a short wait — this is usually a transient response-corruption issue.","Run the request manually (curl https://api.coingecko.com/api/v3/global) to inspect the raw body and see if it is HTML/Cloudflare content.","Add or refresh a browser-like User-Agent / use a Pro API key if Cloudflare challenges are recurring.","Check for a proxy or SSL-inspecting appliance mangling the response and bypass it.","Clear any stale DNS/VPN interference and retry from a different network."],"exampleFix":"// caller: tolerate transient malformed responses\n// before\nconst rows = await runCli('coingecko', 'global');\n// after\nlet rows;\ntry { rows = await runCli('coingecko', 'global'); }\ncatch (e) {\n  if (String(e.message).includes('malformed JSON')) await sleep(1000);\n  rows = await runCli('coingecko', 'global');\n}","handlingStrategy":"retry","validationCode":"const ok = await fetch('https://api.coingecko.com/api/v3/ping').then(r => r.ok).catch(() => false);\nif (!ok) throw new Error('coingecko unreachable right now');","typeGuard":"function isJsonObject(v) { return typeof v === 'object' && v !== null && !Array.isArray(v); }","tryCatchPattern":"try {\n  rows = await runCli('coingecko', 'global');\n} catch (e) {\n  if (String(e.message).includes('malformed JSON')) {\n    await new Promise(r => setTimeout(r, 2000));\n    rows = await runCli('coingecko', 'global');\n  } else throw e;\n}","preventionTips":["Prefer a paid/Pro API key to avoid Cloudflare HTML challenges","Route API traffic outside of inspecting proxies","Retry with exponential backoff on parse failures","Verify connectivity with /ping before long batch runs"],"tags":["network","http","json-parsing","api-response"],"backgroundTag":"malformed-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}