{"record":{"id":"0954d57063363517","repo":"jackwener/OpenCLI","slug":"lobsters-limit-must-be-a-positive-integer","errorCode":null,"errorMessage":"lobsters limit must be a positive integer","messagePattern":"lobsters limit must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/lobsters/domain.js","lineNumber":27,"sourceCode":"\nconst DOMAIN_PATTERN = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;\n\nfunction requireDomain(value) {\n    const s = String(value ?? '').trim().toLowerCase();\n    if (!s) {\n        throw new ArgumentError('lobsters domain is required (e.g. \"github.com\" or \"arxiv.org\")');\n    }\n    if (!DOMAIN_PATTERN.test(s)) {\n        throw new ArgumentError(`lobsters domain \"${value}\" is not a valid hostname`);\n    }\n    return s;\n}\n\nfunction requireBoundedInt(value, defaultValue, maxValue) {\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('lobsters limit must be a positive integer');\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`lobsters limit must be <= ${maxValue}`);\n    }\n    return n;\n}\n\ncli({\n    site: 'lobsters',\n    name: 'domain',\n    access: 'read',\n    description: 'Lobste.rs stories submitted from a specific domain',\n    domain: 'lobste.rs',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'domain', positional: true, required: true, help: 'Source domain (e.g. github.com, arxiv.org, blog.cloudflare.com)' },\n        { name: 'limit', type: 'int', default: 20, help: 'Number of stories (1-25 — single page)' },","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lobsters/domain.js#L9-L45","documentation":"Thrown by requireBoundedInt() when the limit value (or its Number() coercion) is not an integer or is <= 0. The lobsters limit option must be a positive whole number used to cap the number of fetched stories.","triggerScenarios":"Calling limit() with undefined when no defaultValue was provided, NaN, 'abc', 0, -5, 2.5, or a non-numeric string like 'ten'.","commonSituations":"CLI flag parsed from a string flag that was omitted (empty string coerces to NaN); users pass '0' expecting 'unlimited'; decimal input like '10.5'; locale-formatted numbers with commas ('1,000' coerces to NaN).","solutions":["Pass a positive integer, e.g. limit(25) or `--limit 25`","Omit the option to fall back to the configured defaultValue","Parse and sanitize user input with Number.parseInt and validate Number.isInteger(n) && n > 0 first","Replace 'unlimited'/0-style requests with a large finite value within the allowed max"],"exampleFix":"// before\nawait cli.limit(opts.limit); // opts.limit === '0'\n// after\nconst n = Number.parseInt(opts.limit, 10);\nawait cli.limit(Number.isInteger(n) && n > 0 ? n : undefined);","handlingStrategy":"validation","validationCode":"function toPositiveInt(v, fallback) {\n  if (v == null) return fallback;\n  const n = typeof v === 'number' ? v : Number(v);\n  return Number.isInteger(n) && n > 0 ? n : fallback;\n}\nawait cli.limit(toPositiveInt(opts.limit, 25));","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await cli.limit(rawLimit);\n} catch (err) {\n  if (err instanceof ArgumentError && /limit must be a positive integer/.test(err.message)) {\n    console.error(`--limit must be a positive whole number, got: ${rawLimit}`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Parse CLI strings with Number.parseInt(value, 10) and check Number.isNaN before passing","Reject 'unlimited' and 0 from user input; map them to a sensible finite default","Sanitize locale formatting (strip commas) before numeric coercion"],"tags":["argument-error","validation","cli","numeric-input"],"backgroundTag":"invalid-number-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}