{"record":{"id":"68c4156f0adee411","repo":"jackwener/OpenCLI","slug":"homebrew-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"homebrew ${label} must be a positive integer","messagePattern":"homebrew (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/homebrew/utils.js","lineNumber":26,"sourceCode":"\nexport const BREW_BASE = 'https://formulae.brew.sh/api';\nconst UA = 'opencli-homebrew-adapter (+https://github.com/jackwener/opencli)';\n\n// Homebrew formula / cask tokens — letters / digits / `_-.+@` (`gcc@13`,\n// `imagemagick@6`, `c++`, `0-ad`, `php-cs-fixer`).\nconst TOKEN = /^[A-Za-z0-9][A-Za-z0-9._+@-]*$/;\n\nexport function requireString(value, label) {\n    const s = String(value ?? '').trim();\n    if (!s) throw new ArgumentError(`homebrew ${label} cannot be empty`);\n    return s;\n}\n\nexport function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const n = typeof raw === 'number' ? raw : Number(raw);\n    if (!Number.isInteger(n) || n <= 0) {\n        throw new ArgumentError(`homebrew ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`homebrew ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport function requireToken(value, label) {\n    const s = String(value ?? '').trim();\n    if (!s) {\n        throw new ArgumentError(`homebrew ${label} is required (e.g. \"wget\", \"gcc@13\", \"firefox\")`);\n    }\n    if (s.length > 100 || !TOKEN.test(s)) {\n        throw new ArgumentError(\n            `homebrew ${label} \"${value}\" is not a valid token`,\n            'Use letters / digits / \"_-.+@\", starting with a letter or digit (max 100 chars).',\n        );\n    }","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/homebrew/utils.js#L8-L44","documentation":"requireBoundedInt coerces its input to a number and throws ArgumentError('homebrew <label> must be a positive integer') when the value is not an integer or is <= 0. It protects numeric options like limit from non-numeric or non-positive input.","triggerScenarios":"Passing --limit abc, --limit 0, --limit -5, --limit 3.5, or an empty string that coerces to NaN.","commonSituations":"Typo in a CLI flag value, users expecting 'all' or 'max' as a valid limit, scripts interpolating unset variables into the flag.","solutions":["Provide a positive whole number for the option (e.g. --limit 30)","Omit the option entirely to use the default (e.g. 30)","Coerce/validate the value with Number.isInteger before calling","Catch ArgumentError and print usage showing accepted range"],"exampleFix":"// before\nconst limit = args.limit || '';\n// after\nconst n = Number(args.limit);\nif (!Number.isInteger(n) || n <= 0) throw new Error('--limit must be a positive integer');","handlingStrategy":"validation","validationCode":"function parsePositiveInt(raw) {\n  const n = typeof raw === 'number' ? raw : Number(raw);\n  if (!Number.isInteger(n) || n <= 0) {\n    throw new Error(`limit must be a positive integer, got ${JSON.stringify(raw)}`);\n  }\n  return n;\n}","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await homebrewPopular({ limit: rawLimit });\n} catch (err) {\n  if (err instanceof ArgumentError && /positive integer/.test(err.message)) {\n    console.error('--limit must be a whole number > 0');\n    process.exitCode = 2;\n    return;\n  }\n  throw err;\n}","preventionTips":["Sanitize CLI flag values with Number() before passing them","Reject non-numeric strings like 'all'/'max' at the CLI layer","Default to the built-in default (omit the option) when unsure","Validate with Number.isInteger in scripts before calling"],"tags":["validation","argument-error","numeric-input"],"backgroundTag":"invalid-argument-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}