{"record":{"id":"053696e5c8a443ae","repo":"jackwener/OpenCLI","slug":"label-must-be-a-positive-integer-053696","errorCode":null,"errorMessage":"${label} must be a positive integer","messagePattern":"(.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/stackoverflow/utils.js","lineNumber":23,"sourceCode":"// We always set `site=stackoverflow` and decode the gzipped/HTML body via the\n// returned JSON envelope.\nimport {\n    ArgumentError,\n    CommandExecutionError,\n    EmptyResultError,\n} from '@jackwener/opencli/errors';\n\nexport const SE_API = 'https://api.stackexchange.com/2.3';\nexport const SE_SITE = 'stackoverflow';\n\nconst UA = 'opencli-stackoverflow (+https://github.com/jackwener/opencli)';\n\n/** Validate `limit` per typed-fail-fast convention (no silent clamp). */\nexport function normalizeLimit(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const limit = Number(raw);\n    if (!Number.isInteger(limit) || limit <= 0) {\n        throw new ArgumentError(`${label} must be a positive integer`);\n    }\n    if (limit > maxValue) {\n        throw new ArgumentError(`${label} must be <= ${maxValue}`);\n    }\n    return limit;\n}\n\nexport function requireString(value, label) {\n    const raw = String(value ?? '').trim();\n    if (!raw) {\n        throw new ArgumentError(`${label} cannot be empty`);\n    }\n    return raw;\n}\n\n/** Fetch a Stack Exchange API endpoint and return parsed JSON envelope. */\nexport async function seFetch(path, { searchParams } = {}) {\n    const url = new URL(path.startsWith('http') ? path : `${SE_API}${path.startsWith('/') ? '' : '/'}${path}`);","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/stackoverflow/utils.js#L5-L41","documentation":"ArgumentError from normalizeLimit in clis/stackoverflow/utils.js when a --limit value is not a positive integer. By design the helper never silently clamps: Number.isInteger(limit) must be true and limit must be > 0. Note Number('') === 0 and Number('3.5') is fractional, both of which fail.","triggerScenarios":"`--limit 0`, `--limit -5`, `--limit abc`, `--limit 3.5`, `--limit ''`, or a script passing undefined combined with a non-numeric string.","commonSituations":"Computing a limit from user input or a config file where the value is a string like '20 ' or empty; shell passing an empty flag (`--limit=`); NaN from upstream arithmetic.","solutions":["Pass a positive integer, e.g. `--limit 20`.","In scripts, coerce and validate first: const n = Math.trunc(Number(v)); if (!Number.isInteger(n) || n <= 0) ...","Omit the flag to use the command's default limit (e.g. 20).","If the value comes from a config file, fix the entry to a plain integer string."],"exampleFix":"// before\nstackoverflow tag javascript --limit \"\"\n// after\nstackoverflow tag javascript --limit 20","handlingStrategy":"validation","validationCode":"function toLimit(v, dflt = 20) {\n  if (v == null || v === '') return dflt;\n  const n = Number(v);\n  if (!Number.isInteger(n) || n <= 0) throw new TypeError(`limit must be a positive integer, got ${JSON.stringify(v)}`);\n  return n;\n}","typeGuard":"function isPositiveInt(v) { return Number.isInteger(v) && v > 0; }","tryCatchPattern":"try {\n  await run({ limit });\n} catch (e) {\n  if (e.name === 'ArgumentError' && e.message.includes('must be a positive integer')) {\n    return run({ limit: 20 }); // fall back to default\n  }\n  throw e;\n}","preventionTips":["Omit --limit to use the command default instead of passing empty values.","Coerce config strings with Number() and validate integrality before invoking.","Watch for shell quoting bugs like `--limit \"\"` or `--limit= `.","Remember there is no silent clamping — invalid values always fail fast."],"tags":["argument-validation","input-validation","cli"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}