{"record":{"id":"fbe4e55d8e3fe1be","repo":"affaan-m/ECC","slug":"flagname-must-be-a-positive-integer","errorCode":null,"errorMessage":"${flagName} must be a positive integer","messagePattern":"(.+?) must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"scripts/loop-status.js","lineNumber":59,"sourceCode":"  const value = args[index + 1];\n  if (!value || value.startsWith('--')) {\n    throw new Error(`${flagName} requires a value`);\n  }\n  return value;\n}\n\nfunction readPositiveNumber(value, flagName) {\n  const number = Number(value);\n  if (!Number.isFinite(number) || number <= 0) {\n    throw new Error(`${flagName} must be a positive number`);\n  }\n  return number;\n}\n\nfunction readPositiveInteger(value, flagName) {\n  const number = readPositiveNumber(value, flagName);\n  if (!Number.isInteger(number)) {\n    throw new Error(`${flagName} must be a positive integer`);\n  }\n  return number;\n}\n\nfunction parseArgs(argv) {\n  const args = argv.slice(2);\n  const options = {\n    bashTimeoutSeconds: DEFAULT_BASH_TIMEOUT_SECONDS,\n    exitCode: false,\n    home: null,\n    json: false,\n    limit: DEFAULT_LIMIT,\n    now: null,\n    showHelp: false,\n    transcriptPaths: [],\n    watch: false,\n    watchCount: null,\n    wakeGraceMultiplier: DEFAULT_WAKE_GRACE_MULTIPLIER,","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/loop-status.js#L41-L77","documentation":"readPositiveInteger delegates to readPositiveNumber and then additionally requires Number.isInteger, rejecting fractions and NaN. It backs the flags that conceptually count things: --limit and --watch-count. A value like 1.5 or '3.0' parsed loosely will throw here.","triggerScenarios":"Passing a fractional count: `--limit 1.5` or `--watch-count 2.5`. Passing a non-integer string like 'abc' or ''. Passing 0 or a negative integer (caught first by the >0 check in readPositiveNumber).","commonSituations":"Scripting a computed value that occasionally yields a float, e.g. `--limit $((total/2))` where total is odd (this stays integer, but expressions using bc/awk can leak decimals). Copying a decimal from a config that mixed up --limit with --watch-interval-seconds.","solutions":["Pass a positive integer: `--limit 50`, `--watch-count 10`.","Floor/truncate computed values before passing: `--limit \"$(( TOTAL / STEP ))\"`.","If you truly want fractional behaviour, switch to a flag backed by readPositiveNumber.","Omit the flag to use DEFAULT_LIMIT / the watch default."],"exampleFix":"# before\nnode scripts/loop-status.js --limit 25.5\n\n# after\nnode scripts/loop-status.js --limit 25","handlingStrategy":"validation","validationCode":"function isPositiveInt(v) { const n = Number(v); return Number.isInteger(n) && n > 0; }\nfunction validateCounts(flagMap) {\n  for (const [flag, raw] of Object.entries(flagMap)) {\n    if (raw !== undefined && !isPositiveInt(raw)) throw new Error(`${flag} must be a positive integer`);\n  }\n}","typeGuard":"/** @returns {n is number} */\nfunction isPositiveIntGuard(n) { return Number.isInteger(n) && n > 0; }","tryCatchPattern":"try { parseArgs(process.argv); }\ncatch (err) { if (/must be a positive integer/.test(err.message)) { console.error(err.message); printHelp(2); } else throw err; }","preventionTips":["Compute counts with integer arithmetic to avoid leaking decimals.","Prefer omitting the flag to accept the documented default.","Validate numeric env-derived values before passing them through."],"tags":["cli","argument-parsing","numeric-validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}