{"record":{"id":"f6588930e7a3e5d7","repo":"jackwener/OpenCLI","slug":"limit-must-be-a-positive-integer-f65889","errorCode":null,"errorMessage":"limit must be a positive integer","messagePattern":"limit must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/top.js","lineNumber":22,"sourceCode":"\ncli({\n  site: 'coingecko',\n  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    }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/top.js#L4-L40","documentation":"This ArgumentError is thrown before any network call when the limit argument, after Number() coercion, is not a positive integer (0, negative, NaN, fractional). The library enforces that per_page must be a valid positive integer because CoinGecko requires one. It fails fast so no request is wasted.","triggerScenarios":"--limit 0, --limit -5, --limit 2.5, --limit 'abc' (Number('abc') = NaN fails Number.isInteger), or limit omitted and a default of 0/undefined leaking in from a caller.","commonSituations":"Shell variables interpolating empty strings ('' -> 0? actually '' -> 0 via Number, fails); typos like 'l0'; passing floats from scripted calls; config files with limit: null becoming NaN? (Number(null)=0, non-positive).","solutions":["Pass a whole number >= 1, e.g. --limit 10 (the default).","Check the shell/config value for typos, empty strings, or units ('20x').","Coerce safely in your caller: limit = parseInt(raw, 10) and validate before invoking.","If you need 'all coins', call repeatedly with per_page=250 and page=1..N instead of a huge limit."],"exampleFix":"// before\nawait runCli('coingecko', 'top', ['--limit', process.env.TOP_N]);\n// after\nconst n = parseInt(process.env.TOP_N ?? '10', 10);\nif (!Number.isInteger(n) || n <= 0) throw new Error('TOP_N must be a positive integer');\nawait runCli('coingecko', 'top', ['--limit', String(n)]);","handlingStrategy":"validation","validationCode":"function parseLimit(raw) {\n  const n = Number(raw);\n  if (!Number.isInteger(n) || n <= 0) throw new Error(`limit must be a positive integer, got ${JSON.stringify(raw)}`);\n  return n;\n}\nconst limit = parseLimit(args.limit ?? 10);","typeGuard":"function isPositiveInt(v) { return Number.isInteger(v) && v > 0; }","tryCatchPattern":"try {\n  rows = await runCli('coingecko', 'top', ['--limit', limit]);\n} catch (e) {\n  if (/limit must be a positive integer/.test(e.message)) {\n    console.error('Bad --limit; using default 10');\n    rows = await runCli('coingecko', 'top', ['--limit', '10']);\n  } else throw e;\n}","preventionTips":["Use parseInt(value, 10) and check isNaN before passing limits","Sanitize environment/config values that feed --limit","Never pass raw user strings straight through to numeric args","Add input validation at the CLI/script boundary"],"tags":["validation","argument-error","input-validation"],"backgroundTag":"invalid-parameter-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}