{"record":{"id":"d46ef34c55afd5ba","repo":"jackwener/OpenCLI","slug":"limit-must-be-a-positive-integer-got-parsed","errorCode":null,"errorMessage":"--limit must be a positive integer, got ${parsed}","messagePattern":"--limit must be a positive integer, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/rednote/notifications.js","lineNumber":31,"sourceCode":"import { ArgumentError, CommandExecutionError } from '@jackwener/opencli/errors';\n\nconst NOTIFICATION_TYPES = new Set(['mentions', 'likes', 'connections']);\n\nfunction parseNotificationType(raw) {\n    const type = String(raw ?? 'mentions');\n    if (!NOTIFICATION_TYPES.has(type)) {\n        throw new ArgumentError(`--type must be one of mentions, likes, or connections, got ${JSON.stringify(raw)}`);\n    }\n    return type;\n}\n\nfunction parseLimit(raw) {\n    const parsed = Number(raw ?? 20);\n    if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {\n        throw new ArgumentError(`--limit must be a positive integer, got ${JSON.stringify(raw)}`);\n    }\n    if (parsed < 1) {\n        throw new ArgumentError(`--limit must be a positive integer, got ${parsed}`);\n    }\n    return parsed;\n}\n\nconst READ_NOTIFICATIONS_JS = `\n  (async (type) => {\n    let pinia = null;\n    const probe = (el) => el?.__vue_app__?.config?.globalProperties?.$pinia ?? null;\n    pinia = probe(document.querySelector('#app'));\n    if (!pinia) {\n      for (const el of document.querySelectorAll('*')) {\n        pinia = probe(el);\n        if (pinia) break;\n      }\n    }\n    if (!pinia || !pinia._s) return { error: 'no_pinia' };\n    const store = pinia._s.get('notification');\n    if (!store) return { error: 'no_notification_store' };","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rednote/notifications.js#L13-L49","documentation":"parseLimit throws ArgumentError when the value coerces to a finite integer but is below the allowed minimum of 1 (e.g. 0, -5). The message embeds the coerced number rather than the raw input, distinguishing it from the non-integer branch of the same guard.","triggerScenarios":"Passing --limit 0 or a negative integer (e.g. --limit -1) to the rednote notifications command. Note that '0' as a string coerces to 0 and lands here, not in the non-integer branch.","commonSituations":"Config files or scripts that compute a limit via subtraction or slicing math that yields 0, users who think 0 means 'unlimited', or off-by-one loop calculations passed through to the CLI.","solutions":["Pass --limit with a value of at least 1","If 0 should mean 'unlimited', clamp before invoking: Math.max(1, parsed)","Check scripts computing the limit dynamically for arithmetic that can produce 0 or negatives"],"exampleFix":"// before\nconst limit = items.length; // can be 0\nrun(['rednote','notifications','--limit', limit]);\n// after\nconst limit = Math.max(1, items.length);\nrun(['rednote','notifications','--limit', limit]);","handlingStrategy":"validation","validationCode":"const n = Number(raw ?? 20); if (Number.isInteger(n) && n < 1) throw new Error(`--limit must be >= 1, got ${n}`);","typeGuard":"const isPositiveInt = (v) => Number.isInteger(v) && v >= 1;","tryCatchPattern":"try { await runNotifications({ limit }); } catch (e) { if (e instanceof ArgumentError && /positive integer/.test(e.message)) { limit = Math.max(1, limit); return runNotifications({ limit }); } throw e; }","preventionTips":["Never use 0 to mean 'unlimited'; clamp with Math.max(1, n)","Check arithmetic that computes limits for values that can reach 0 or below","Document limit semantics in scripts that wrap the CLI"],"tags":["cli","argument-validation","range-check"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}