{"record":{"id":"469974eae6016c82","repo":"jackwener/OpenCLI","slug":"packagist-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"packagist ${label} must be a positive integer","messagePattern":"packagist (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/packagist/utils.js","lineNumber":24,"sourceCode":"import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\n\nexport const PACKAGIST_BASE = 'https://packagist.org';\nconst UA = 'opencli-packagist-adapter (+https://github.com/jackwener/opencli)';\n\n// Each segment of a Composer package name (`vendor` and `package`).\nconst SEGMENT = /^[a-z0-9]([_.-]?[a-z0-9]+)*$/;\n\nexport function requireString(value, label) {\n    const s = String(value ?? '').trim();\n    if (!s) throw new ArgumentError(`packagist ${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(`packagist ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`packagist ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport function requirePackageName(value) {\n    const raw = String(value ?? '').trim().toLowerCase();\n    if (!raw) {\n        throw new ArgumentError('packagist package name is required (e.g. \"symfony/console\", \"monolog/monolog\")');\n    }\n    const slash = raw.indexOf('/');\n    if (slash <= 0 || slash === raw.length - 1) {\n        throw new ArgumentError(\n            `packagist package \"${value}\" must be \"<vendor>/<package>\"`,\n            'Both segments are required (Composer convention).',\n        );","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/packagist/utils.js#L6-L42","documentation":"requireBoundedInt coerces its input with Number() and throws this ArgumentError when the result is not an integer or is <= 0. The adapter uses it to validate the `limit` option so only sensible positive page sizes are sent to Packagist. Values like 0, -1, NaN, 'abc', or 2.5 all land here.","triggerScenarios":"Calling limit (which calls requireBoundedInt) with limit=0, a negative number, a non-numeric string like 'ten', a float like 1.5, or a string like '' that coerces to NaN.","commonSituations":"User passes --limit 0 or --limit abc on the CLI; a config file stores limit as a string that fails Number() parsing; code computes a limit via arithmetic that yields NaN (e.g. parseInt of malformed input).","solutions":["Pass a positive integer (>= 1) for the labeled option.","If the value is a string, parse it with parseInt/Number and verify Number.isInteger before calling.","Clamp user-supplied values: Math.max(1, Math.floor(n)).","Catch ArgumentError and fall back to a sane default limit."],"exampleFix":"// before\nrun({ limit: opts.limit }); // '20x' -> NaN -> throws\n\n// after\nconst n = Number.parseInt(opts.limit ?? '10', 10);\nrun({ limit: Number.isInteger(n) && n > 0 ? n : 10 });","handlingStrategy":"validation","validationCode":"function toPositiveInt(v, dflt = 10) {\n  if (v == null) return dflt;\n  const n = typeof v === 'number' ? v : Number(v);\n  return Number.isInteger(n) && n > 0 ? n : dflt;\n}","typeGuard":"const isPositiveInt = (v) => typeof v === 'number' && Number.isInteger(v) && v > 0;","tryCatchPattern":"try {\n  await run({ limit });\n} catch (e) {\n  if (e instanceof ArgumentError && /positive integer/.test(e.message)) {\n    return run({ limit: 10 });\n  }\n  throw e;\n}","preventionTips":["Coerce CLI flags with parseInt and validate with Number.isInteger before use.","Reject NaN early — Number('') and Number('abc') are the usual culprits.","Clamp defaults: Math.max(1, Math.floor(raw)).","Document valid ranges in --help output."],"tags":["argument-validation","type-mismatch","integer","packagist"],"backgroundTag":"invalid-argument-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}