{"record":{"id":"3bfd4c4c754d4b27","repo":"jackwener/OpenCLI","slug":"zhihu-collection-name-must-be-a-non-negative","errorCode":null,"errorMessage":"zhihu collection --${name} must be a non-negative integer","messagePattern":"zhihu collection --(.+?) must be a non-negative integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/zhihu/collection.js","lineNumber":17,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, AuthRequiredError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\nimport { log } from '@jackwener/opencli/logger';\nimport { stripHtml } from './text.js';\n\nfunction validatePositiveInt(value, name) {\n  const n = Number(value);\n  if (!Number.isInteger(n) || n <= 0) {\n    throw new ArgumentError(`zhihu collection --${name} must be a positive integer`, 'Example: opencli zhihu collection 83283292 --limit 20');\n  }\n  return n;\n}\n\nfunction validateNonNegativeInt(value, name) {\n  const n = Number(value);\n  if (!Number.isInteger(n) || n < 0) {\n    throw new ArgumentError(`zhihu collection --${name} must be a non-negative integer`, 'Example: opencli zhihu collection 83283292 --offset 0');\n  }\n  return n;\n}\n\nasync function fetchCollectionPage(page, collectionId, offset, limit) {\n  const url = `https://www.zhihu.com/api/v4/collections/${collectionId}/items?offset=${offset}&limit=${limit}`;\n  const data = await page.evaluate(`\n    (async () => {\n      const r = await fetch(${JSON.stringify(url)}, { credentials: 'include' });\n      if (!r.ok) return { __httpError: r.status };\n      return await r.json();\n    })()\n  `);\n\n  if (!data || data.__httpError) {\n    const status = data?.__httpError;\n    if (status === 401 || status === 403) {\n      throw new AuthRequiredError('www.zhihu.com', 'Failed to fetch collection data from Zhihu. Please ensure you are logged in.');","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/zhihu/collection.js#L1-L35","documentation":"validateNonNegativeInt (called by pageOffset for options like --offset) throws ArgumentError when the value is not an integer or is negative. Unlike the limit validator, zero is allowed here since offset 0 is valid. Validation happens before any fetch.","triggerScenarios":"Passing `--offset -1`, `--offset 1.5`, `--offset x`, or an empty value to `opencli zhihu collection`; pageOffset() applies validateNonNegativeInt to the raw option.","commonSituations":"Pagination loop math producing negative offsets (e.g. `offset = (page-2)*limit` on page 1); unset shell variable rendering `--offset \"\"`; parsing numbers with signs or whitespace from config files.","solutions":["Pass a non-negative integer, e.g. `--offset 0`.","Clamp computed offsets: `Math.max(0, computedOffset)` before passing.","Default unset variables: `${OFFSET:-0}` in shell.","Catch ArgumentError and sanitize with Number.parseInt plus a >= 0 check before invoking."],"exampleFix":"// before\nopencli zhihu collection 83283292 --offset -10\n// ArgumentError: --offset must be a non-negative integer\n// after\nconst offset = Math.max(0, (page - 1) * limit);\nopencli zhihu collection 83283292 --offset ${offset}","handlingStrategy":"validation","validationCode":"function toNonNegativeInt(v) { const n = Number(v); if (!Number.isInteger(n) || n < 0) throw new Error(`--offset must be a non-negative integer, got: ${JSON.stringify(v)}`); return n; }","typeGuard":"function isNonNegativeInt(v) { return Number.isInteger(Number(v)) && Number(v) >= 0; }","tryCatchPattern":"try { await collection(args); } catch (e) { if (/must be a non-negative integer/.test(e.message)) { args.offset = Math.max(0, parseInt(args.offset, 10) || 0); return collection(args); } throw e; }","preventionTips":["Clamp computed pagination offsets with Math.max(0, offset)","Default unset variables: ${OFFSET:-0}","Sanitize numeric inputs from JSON/YAML configs before passing","Remember offset 0 is valid — only negatives and non-integers fail"],"tags":["validation","arguments","cli","pagination","zhihu"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}