{"record":{"id":"8e0e347c9798941d","repo":"jackwener/OpenCLI","slug":"huodongxing-limit-must-be-a-positive-integer","errorCode":null,"errorMessage":"huodongxing limit must be a positive integer","messagePattern":"huodongxing limit must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/huodongxing/events.js","lineNumber":27,"sourceCode":"  'id',\n  'title',\n  'time',\n  'eventType',\n  'city',\n  'location',\n  'organizer',\n  'url',\n];\n\nfunction cleanText(value) {\n  return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nexport function requireLimit(value) {\n  const raw = value ?? 20;\n  const limit = typeof raw === 'number' ? raw : Number(String(raw).trim());\n  if (!Number.isInteger(limit) || limit <= 0) {\n    throw new ArgumentError('huodongxing limit must be a positive integer');\n  }\n  if (limit > MAX_LIMIT) {\n    throw new ArgumentError(`huodongxing limit must be <= ${MAX_LIMIT}`);\n  }\n  return limit;\n}\n\nfunction appendIfPresent(params, name, value) {\n  const text = cleanText(value);\n  if (text) params.set(name, text);\n}\n\nfunction dateOrdinal(year, month, day) {\n  return Math.floor(Date.UTC(year, month - 1, day) / 86400000);\n}\n\nfunction parseYmd(value) {\n  const match = cleanText(value).match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/huodongxing/events.js#L9-L45","documentation":"requireLimit normalizes the huodongxing events `limit` option (default 20) into a positive integer. It throws this ArgumentError when the value is not an integer or is <= 0 — e.g. non-numeric strings, floats, zero, negatives, or NaN from unparsable text. This validates input before it reaches the scraper's pagination logic.","triggerScenarios":"limit('abc'), limit(0), limit(-5), limit(2.5), limit(''), limit(undefined as 'undefined') — any call path where the limit option is a string/number failing Number.isInteger && > 0. Note the error message says 'positive integer' but the code also rejects NaN produced by Number('abc').","commonSituations":"CLI flag parsing delivering strings like 'ten' or '1..5'; config files with quoted or empty values; users passing 0 expecting 'unlimited'; float math upstream (e.g. items.length/2) leaking into limit.","solutions":["Pass a positive integer (1–50): limit(10) or limit('10') both work since strings are coerced via Number().","Validate/coerce the option at the call site: Number.parseInt(value, 10) and check Number.isInteger before calling.","Replace 0/negative values meant as 'all' with the maximum (50) or omit the option to use the default 20."],"exampleFix":"// before\nawait events({ limit: 'ten' });   // ArgumentError\nawait events({ limit: 0 });       // ArgumentError\n// after\nconst n = Number.parseInt(userLimit, 10);\nawait events({ limit: Number.isInteger(n) && n > 0 ? n : 20 });","handlingStrategy":"validation","validationCode":"function parseLimit(value, { max = 50, def = 20 } = {}) {\n  const n = typeof value === 'number' ? value : Number(String(value ?? '').trim());\n  return Number.isInteger(n) && n > 0 ? n : def;\n}\nconst limit = parseLimit(userInput);","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await events({ limit });\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.includes('limit must be a positive integer')) {\n    await events({ limit: 20 }); // fall back to default\n  } else throw err;\n}","preventionTips":["Coerce CLI/config values with Number.parseInt(value, 10) before passing.","Reject 0/negative values early — they mean 'unlimited' to users but are invalid here.","Keep limit values as integers end-to-end; avoid float math upstream.","Default to 20 (the library default) when input is absent."],"tags":["argument-validation","invalid-limit","cli"],"backgroundTag":"invalid-numeric-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}