{"record":{"id":"347c9f1dae1f347d","repo":"jackwener/OpenCLI","slug":"coingecko-global-returned-no-data-envelope","errorCode":null,"errorMessage":"coingecko global returned no data envelope","messagePattern":"coingecko global returned no data envelope","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/global.js","lineNumber":48,"sourceCode":"        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,\n            btcDominancePct: data?.market_cap_percentage?.btc != null ? Number(data.market_cap_percentage.btc) : null,\n            ethDominancePct: data?.market_cap_percentage?.eth != null ? Number(data.market_cap_percentage.eth) : null,\n            activeCryptocurrencies: data.active_cryptocurrencies != null ? Number(data.active_cryptocurrencies) : null,\n            markets: data.markets != null ? Number(data.markets) : null,","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/global.js#L30-L66","documentation":"This CommandExecutionError is thrown when the /global response parses as JSON but lacks the expected { data: {...} } envelope. The library treats a missing 'data' object as an unusable response rather than trying to guess fields. It indicates the API's response shape changed or returned a JSON error payload.","triggerScenarios":"resp.json() succeeded but body?.data is undefined/null: the API returned a JSON error object, an empty body ('{}'), or a restructured payload without the 'data' wrapper.","commonSituations":"CoinGecko deprecating or changing the /global schema; a transparent proxy returning its own JSON error (e.g. quota exhausted JSON); API returning {status:{error_code:...}} error envelopes for rejected requests.","solutions":["Print the raw body (curl the endpoint) to see what JSON was actually returned.","Check CoinGecko API status/changelog for schema changes to /global.","If an API error envelope is returned, address the underlying cause (quota, auth, blocked IP).","Pin or update the opencli library version so its parsing matches the current API schema.","Retry later if CoinGecko is mid-incident; envelope-less responses are often transient."],"exampleFix":"// before\nconst body = JSON.parse(raw);\nconst caps = body.total_market_cap;\n// after\nconst data = body?.data;\nif (!data) throw new Error('unexpected /global envelope: ' + JSON.stringify(body).slice(0, 200));\nconst caps = data.total_market_cap;","handlingStrategy":"type-guard","validationCode":"const probe = await fetch('https://api.coingecko.com/api/v3/global').then(r => r.json());\nif (!probe?.data) console.warn('coingecko /global envelope missing — API shape may have changed');","typeGuard":"function hasGlobalEnvelope(body) {\n  return typeof body === 'object' && body !== null && 'data' in body && typeof body.data === 'object';\n}","tryCatchPattern":"try {\n  rows = await runCli('coingecko', 'global');\n} catch (e) {\n  if (String(e.message).includes('no data envelope')) {\n    console.error('API schema drift or JSON error payload — inspect raw response');\n  }\n  throw e;\n}","preventionTips":["Pin library versions and read CoinGecko changelog for /global changes","Log the raw body when envelope errors occur to aid diagnosis","Handle JSON error envelopes ({status:{error_code}}) upstream","Add an integration test asserting the /global envelope shape"],"tags":["api-response","schema-change","json"],"backgroundTag":"unexpected-response-schema","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}