{"record":{"id":"d4a9dd04aadacea7","repo":"jackwener/OpenCLI","slug":"limit-must-be-250-coingecko-per-page-upper-bou","errorCode":null,"errorMessage":"limit must be <= 250 (CoinGecko per_page upper bound)","messagePattern":"limit must be <= 250 \\(CoinGecko per_page upper bound\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/top.js","lineNumber":25,"sourceCode":"  name: 'top',\n  access: 'read',\n  description: '按市值排序的加密货币行情（默认 USD）',\n  domain: 'api.coingecko.com',\n  strategy: Strategy.PUBLIC,\n  browser: false,\n  args: [\n    { name: 'currency', type: 'string', default: 'usd', help: '计价币种 (usd / cny / eur / jpy ...)' },\n    { name: 'limit',    type: 'int',    default: 10,    help: '返回数量（默认 10，最多 250）' },\n  ],\n  columns: ['rank', 'symbol', 'name', 'price', 'change24hPct', 'marketCap', 'volume24h', 'high24h', 'low24h'],\n  func: async (args) => {\n    const currency = String(args.currency ?? 'usd').toLowerCase();\n    const limit = Number(args.limit ?? 10);\n    if (!Number.isInteger(limit) || limit <= 0) {\n      throw new ArgumentError('limit must be a positive integer');\n    }\n    if (limit > 250) {\n      throw new ArgumentError('limit must be <= 250 (CoinGecko per_page upper bound)');\n    }\n\n    const url = new URL('https://api.coingecko.com/api/v3/coins/markets');\n    url.searchParams.set('vs_currency', currency);\n    url.searchParams.set('order', 'market_cap_desc');\n    url.searchParams.set('per_page', String(limit));\n    url.searchParams.set('page', '1');\n    url.searchParams.set('sparkline', 'false');\n\n    let resp;\n    try {\n      resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n    } catch (error) {\n      throw new CommandExecutionError(`coingecko top request failed: ${error?.message || error}`);\n    }\n    if (!resp.ok) throw new CommandExecutionError(`coingecko top failed: HTTP ${resp.status}`);\n    let data;\n    try {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/top.js#L7-L43","documentation":"This ArgumentError is thrown when the requested limit exceeds 250, the maximum per_page value CoinGecko's /coins/markets endpoint accepts. The check runs before the HTTP request so no doomed call is made. To fetch more than 250 coins you must paginate with the page parameter.","triggerScenarios":"--limit 500, --limit 1000, or a config value like 'top 500 coins' passed straight through; Number coercion of a large count from a dashboard config.","commonSituations":"Users expecting the CLI to auto-paginate past 250; scripts copying a coin list length (>250) as the limit; misunderstanding that per_page is capped by the API, not the CLI.","solutions":["Set limit to at most 250 for a single request.","Use the API's pagination: request per_page=250 with page=1,2,3... and merge results for more coins.","Clamp in your caller: limit = Math.min(Math.max(1, n), 250).","If you truly need the whole market, loop pages until an empty array is returned."],"exampleFix":"// before\nawait runCli('coingecko', 'top', ['--limit', '500']);\n// after\nconst limit = Math.min(Math.max(1, Number(raw)), 250);\nawait runCli('coingecko', 'top', ['--limit', String(limit)]);","handlingStrategy":"validation","validationCode":"const n = Number(rawLimit ?? 10);\nif (!Number.isInteger(n) || n < 1 || n > 250) throw new Error(`limit must be 1..250, got ${rawLimit}`);","typeGuard":"function isValidLimit(v) { return Number.isInteger(v) && v >= 1 && v <= 250; }","tryCatchPattern":"try {\n  rows = await runCli('coingecko', 'top', ['--limit', limit]);\n} catch (e) {\n  if (/limit must be <= 250/.test(e.message)) {\n    console.warn('Clamping limit to 250; paginate for more');\n    rows = await runCli('coingecko', 'top', ['--limit', '250']);\n  } else throw e;\n}","preventionTips":["Clamp with Math.min(Math.max(1, n), 250) before calling","Remember CoinGecko caps per_page at 250 — paginate with page for more","Validate dashboard/config coin counts against the 250 cap","Document the 250 max wherever users configure limits"],"tags":["validation","argument-error","api-limits","pagination"],"backgroundTag":"parameter-out-of-range","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}