{"record":{"id":"3e641c1a9e66caf9","repo":"jackwener/OpenCLI","slug":"coingecko-page-must-be-a-positive-integer","errorCode":null,"errorMessage":"coingecko page must be a positive integer","messagePattern":"coingecko page must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/coingecko/exchanges.js","lineNumber":32,"sourceCode":"    domain: 'api.coingecko.com',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'limit', type: 'int', default: 20, help: 'Number of exchanges (1-250, CoinGecko per_page upper bound)' },\n        { name: 'page', type: 'int', default: 1, help: 'Page number (1-based)' },\n    ],\n    columns: ['rank', 'id', 'name', 'trustScore', 'volume24hBtc', 'country', 'yearEstablished', 'url'],\n    func: async (args) => {\n        const limit = Number(args.limit ?? 20);\n        if (!Number.isInteger(limit) || limit <= 0) {\n            throw new ArgumentError('coingecko limit must be a positive integer');\n        }\n        if (limit > 250) {\n            throw new ArgumentError('coingecko limit must be <= 250 (per_page upper bound)');\n        }\n        const page = Number(args.page ?? 1);\n        if (!Number.isInteger(page) || page <= 0) {\n            throw new ArgumentError('coingecko page must be a positive integer');\n        }\n        const url = new URL('https://api.coingecko.com/api/v3/exchanges');\n        url.searchParams.set('per_page', String(limit));\n        url.searchParams.set('page', String(page));\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n        }\n        catch (err) {\n            throw new CommandExecutionError(`coingecko exchanges 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) {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coingecko/exchanges.js#L14-L50","documentation":"The `coingecko exchanges` command requires `page` to be a positive integer (1-based) because it is sent verbatim as the `page` query parameter to CoinGecko's `/api/v3/exchanges` endpoint. The library converts `args.page` with `Number()` and rejects any value that is not an integer or is <= 0 with an ArgumentError, failing fast before any network call.","triggerScenarios":"Calling the exchanges command with page=0, page=-1, page=1.5, a non-numeric string like 'first' or '', or an object/array (Number() yields NaN) — e.g. `coingecko exchanges --page 0` or programmatic invocation `func({ page: 'two' })`.","commonSituations":"Scripts computing page numbers from loops that start at 0 instead of 1, passing user-supplied CLI text without sanitizing, off-by-one pagination math, or defaulting page to 0 as a 'first page' sentinel in another language's convention.","solutions":["Pass a page >= 1: `coingecko exchanges --page 1` (the default is already 1).","Coerce and clamp in your calling code: `page = Math.max(1, Math.floor(Number(rawPage) || 1))`.","If paginating from a 0-based loop index, add 1 before passing: `func({ page: i + 1 })`.","Omit the argument entirely to use the built-in default of 1."],"exampleFix":"// before\nawait exchanges.func({ page: 0 });\n// after\nawait exchanges.func({ page: Math.max(1, Math.floor(Number(userPage) || 1)) });","handlingStrategy":"validation","validationCode":"const page = Math.max(1, Math.floor(Number(rawPage) || 1));\nif (!Number.isInteger(page) || page <= 0) throw new Error(`page must be a positive integer, got ${rawPage}`);","typeGuard":"function isValidPage(v) { const n = Number(v); return Number.isInteger(n) && n > 0; }","tryCatchPattern":null,"preventionTips":["Always use 1-based page numbers with CoinGecko endpoints.","Clamp/normalize user input with Math.max(1, Math.floor(...)) before calling.","Rely on the built-in default (page=1) instead of hand-rolling 'first page' values.","Sanitize CLI/env-derived strings with Number() before passing them as page."],"tags":["argument-validation","input-error","pagination"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}