{"record":{"id":"c5ba277be75b944c","repo":"jackwener/OpenCLI","slug":"limit-must-be-a-positive-integer-got-json-str-c5ba27","errorCode":null,"errorMessage":"--limit must be a positive integer, got ${JSON.stringify(raw)}","messagePattern":"--limit must be a positive integer, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"warning","filePath":"clis/xiaohongshu/feed.js","lineNumber":22,"sourceCode":" * Earlier versions used a `tap` step that called the `fetchFeeds` store action,\n * which fetches the NEXT page of recommendations. Those API items carry no\n * `xsecToken` and do not overlap the first-screen notes, so the feed's URLs\n * could not be passed to `note`/`comments`/`download` (which require a signed\n * URL). The hydrated store, by contrast, holds `entry.xsecToken` for every\n * first-screen note, so a func-mode read yields signed, drill-down-ready URLs.\n *\n * Mirrors rednote/feed.js: the hydrated store is camelCase on both sites\n * (`noteCard.displayTitle`, `interactInfo.likedCount`). This is the SSR store\n * shape, not the snake_case `/homefeed` API response the old tap intercepted.\n */\nimport { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\nimport { unwrapEvaluateResult } from './shared.js';\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 FEEDS_READ_JS = `\n  (() => {\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      // Some builds mount under a different root id; fall back to a full scan\n      // only when the standard mount node misses.\n      for (const el of document.querySelectorAll('*')) {\n        pinia = probe(el);\n        if (pinia) break;","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/feed.js#L4-L40","documentation":"parseLimit coerces the raw --limit CLI value with Number() and requires a finite integer. Non-numeric or non-integer input (e.g. 'abc', 2.5, '') throws ArgumentError with the JSON-stringified raw value.","triggerScenarios":"Calling the feed command with --limit set to a non-integer or non-numeric string, e.g. --limit=abc, --limit=2.5, --limit=''. Note null/undefined are allowed (defaults to 20).","commonSituations":"Shell quoting issues passing '20\\n', users passing floats or words, scripts interpolating empty variables into --limit, config files supplying \"all\" instead of a number.","solutions":["Pass a positive integer: --limit 20","If the value comes from a script/env var, ensure it is a non-empty integer string","Omit --limit entirely to use the default of 20","Trim whitespace/newlines from the value before passing"],"exampleFix":"// before\nxhs feed --limit 2.5\n// after\nxhs feed --limit 25","handlingStrategy":"validation","validationCode":"const n = Number(raw);\nif (raw != null && (!Number.isFinite(n) || !Number.isInteger(n))) throw new Error(`--limit must be an integer, got ${raw}`);","typeGuard":"function isValidLimit(raw) { if (raw == null) return true; const n = Number(raw); return Number.isInteger(n); }","tryCatchPattern":"try {\n  await cli.feed({ limit: rawLimit });\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.startsWith('--limit')) {\n    console.error('Usage: --limit <positive integer>');\n  } else throw err;\n}","preventionTips":["Pass integer strings for --limit; avoid floats and words","Trim shell variables before interpolation","Omit --limit to use the default 20","Validate CLI args in wrapper scripts before invoking"],"tags":["cli","argument-validation"],"backgroundTag":"invalid-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}