{"record":{"id":"d1804b5aab8b8ec5","repo":"jackwener/OpenCLI","slug":"limit-must-be-a-positive-integer-1-max","errorCode":null,"errorMessage":"limit must be a positive integer (1-${max})","messagePattern":"limit must be a positive integer \\(1-(.+?)\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/12306/utils.js","lineNumber":108,"sourceCode":"}\n\nexport function validateDate(value) {\n    if (!DATE_RE.test(String(value ?? ''))) {\n        throw new ArgumentError(`date must be YYYY-MM-DD, got \"${value}\"`);\n    }\n    const [y, m, d] = value.split('-').map(Number);\n    const date = new Date(Date.UTC(y, m - 1, d));\n    if (date.getUTCFullYear() !== y || date.getUTCMonth() !== m - 1 || date.getUTCDate() !== d) {\n        throw new ArgumentError(`date \"${value}\" is not a real calendar date`);\n    }\n    return value;\n}\n\nexport function normalizeLimit(value, defaultValue, max) {\n    if (value === undefined || value === null || value === '') return defaultValue;\n    const n = Number(value);\n    if (!Number.isInteger(n) || n < 1) {\n        throw new ArgumentError(`limit must be a positive integer (1-${max})`);\n    }\n    if (n > max) {\n        throw new ArgumentError(`limit must be <= ${max}`);\n    }\n    return n;\n}\n\n/** Extract Set-Cookie header values into a single `Cookie:` header string. */\nexport function buildCookieHeader(setCookieHeaders) {\n    if (!Array.isArray(setCookieHeaders) || setCookieHeaders.length === 0) return '';\n    return setCookieHeaders\n        .map((line) => line.split(';')[0])\n        .filter(Boolean)\n        .join('; ');\n}\n\nexport async function fetchStationBundle(fetchImpl = fetch) {\n    const resp = await fetchImpl(STATION_BUNDLE_URL, {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/12306/utils.js#L90-L126","documentation":"normalizeLimit() requires the limit to be a positive integer (>= 1) when provided. Non-integers, zero, negatives, and non-numeric strings throw this ArgumentError with the allowed range 1..max.","triggerScenarios":"Passing limit=0, limit=-5, limit=2.5, limit='ten', or limit='3.0' (string that Number() parses to a non-integer-safe value is fine as 3; '2.5' fails) to any command exposing a limit option.","commonSituations":"Config files with limit: 0 meaning 'unlimited' (wrong assumption here), page sizes computed by division yielding floats, or users entering 0 intending 'no limit'.","solutions":["Pass a positive integer between 1 and max, or omit the option entirely to get the default","Round/ceiling computed values with Math.floor/Math.ceil before passing","Treat 'unlimited' as omitting limit rather than 0"],"exampleFix":"// before\nawait query({ limit: 0 });\n// after\nawait query({}); // default limit\n// or\nawait query({ limit: Math.floor(pageSize) });","handlingStrategy":"validation","validationCode":"function isValidLimit(v, max) {\n  if (v === undefined || v === null || v === '') return true; // default applies\n  const n = Number(v);\n  return Number.isInteger(n) && n >= 1 && n <= max;\n}\nif (!isValidLimit(opts.limit, 100)) throw new Error('limit must be a positive integer');","typeGuard":null,"tryCatchPattern":"try {\n  await query({ limit });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('limit must be a positive integer')) {\n    console.error('Supply an integer limit >= 1, or omit it for the default.');\n  } else throw e;\n}","preventionTips":["Coerce and validate numeric options at the CLI/config boundary","Never use 0 to mean 'unlimited' — omit the option instead","Floor computed page sizes before passing"],"tags":["input-validation","argument-error","pagination"],"backgroundTag":"invalid-parameter-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}