{"record":{"id":"fc577f95ea4a38e8","repo":"jackwener/OpenCLI","slug":"label-must-be-a-positive-integer-fc577f","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/weread/book-search.js","lineNumber":28,"sourceCode":"    return String(value || '')\n        .replace(/<[^>]+>/g, '')\n        .replace(/&#x([0-9a-fA-F]+);/gi, (_, n) => String.fromCharCode(parseInt(n, 16)))\n        .replace(/&#(\\d+);/g, (_, n) => String.fromCharCode(Number(n)))\n        .replace(/&nbsp;/g, ' ')\n        .replace(/&amp;/g, '&')\n        .replace(/&quot;/g, '\"')\n        .trim();\n}\n\nfunction normalizeSearchText(value) {\n    return String(value || '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizePositiveInteger(value, defaultValue, label, maxValue) {\n    const raw = value ?? defaultValue;\n    const n = Number(raw);\n    if (!Number.isInteger(n) || n <= 0) {\n        throw new ArgumentError(`${label} must be a positive integer`);\n    }\n    if (maxValue != null && n > maxValue) {\n        throw new ArgumentError(`${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nfunction parseOptionalFiniteNumber(value) {\n    if (value == null || value === '')\n        return null;\n    const n = Number(value);\n    return Number.isFinite(n) ? n : null;\n}\n\nfunction parseHasMore(value) {\n    if (value === true || value === 1 || value === '1')\n        return true;\n    if (value === false || value === 0 || value === '0')","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weread/book-search.js#L10-L46","documentation":"normalizePositiveInteger validates that a numeric CLI option (bookRank, limit, fragmentSize) is a positive integer before use. The library throws ArgumentError when Number(value) is not an integer or is <= 0, i.e. the user passed a fractional, zero, negative, or non-numeric value for that option.","triggerScenarios":"Calling the book-search command with an option such as --book-rank, --limit, or --fragment-size set to 0, -1, 2.5, 'abc', an empty-but-non-null string, or a value that Number() coerces to NaN or Infinity.","commonSituations":"Users typo a flag value (--limit=ten), paste values with trailing spaces or units ('20 pages'), script variables are empty strings rather than unset (empty string coerces to 0), or shell interpolation yields a fractional number.","solutions":["Pass a whole number >= 1 for the offending option","Omit the option entirely so the built-in defaultValue is used (null/undefined falls through via value ?? defaultValue)","Fix the calling script so the variable holds a numeric string, e.g. LIMIT=20 not LIMIT=''","Check the exact label in the message to see which option failed validation"],"exampleFix":"// before\nweread book-search --query zen --limit 0\n// after\nweread book-search --query zen --limit 10","handlingStrategy":"validation","validationCode":"function ensurePositiveInt(v, name) {\n  const n = Number(v);\n  if (!Number.isInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive integer, got: ${JSON.stringify(v)}`);\n  return n;\n}\nensurePositiveInt(opts.limit, 'limit');","typeGuard":"const isPositiveInt = (v) => Number.isInteger(Number(v)) && Number(v) > 0;","tryCatchPattern":"try {\n  await runCommand(['book-search', '--query', q, '--limit', String(limit)]);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('must be a positive integer')) {\n    console.error(`Bad numeric option: ${e.message}`); process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always coerce and validate numeric CLI inputs with Number.isInteger before passing them","Default empty shell variables explicitly (LIMIT=\"${LIMIT:-10}\") so '' never reaches the CLI","Keep numeric values unquoted and free of units/spaces in scripts"],"tags":["validation","cli-arguments","argument-error"],"backgroundTag":"invalid-integer-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}