jackwener/OpenCLI · error · ArgumentError

zhihu collection --${name} must be a non-negative integer

Error message

zhihu collection --${name} must be a non-negative integer

What it means

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.

Source

Thrown at clis/zhihu/collection.js:17

import { cli, Strategy } from '@jackwener/opencli/registry';
import { ArgumentError, AuthRequiredError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
import { log } from '@jackwener/opencli/logger';
import { stripHtml } from './text.js';

function validatePositiveInt(value, name) {
  const n = Number(value);
  if (!Number.isInteger(n) || n <= 0) {
    throw new ArgumentError(`zhihu collection --${name} must be a positive integer`, 'Example: opencli zhihu collection 83283292 --limit 20');
  }
  return n;
}

function validateNonNegativeInt(value, name) {
  const n = Number(value);
  if (!Number.isInteger(n) || n < 0) {
    throw new ArgumentError(`zhihu collection --${name} must be a non-negative integer`, 'Example: opencli zhihu collection 83283292 --offset 0');
  }
  return n;
}

async function fetchCollectionPage(page, collectionId, offset, limit) {
  const url = `https://www.zhihu.com/api/v4/collections/${collectionId}/items?offset=${offset}&limit=${limit}`;
  const data = await page.evaluate(`
    (async () => {
      const r = await fetch(${JSON.stringify(url)}, { credentials: 'include' });
      if (!r.ok) return { __httpError: r.status };
      return await r.json();
    })()
  `);

  if (!data || data.__httpError) {
    const status = data?.__httpError;
    if (status === 401 || status === 403) {
      throw new AuthRequiredError('www.zhihu.com', 'Failed to fetch collection data from Zhihu. Please ensure you are logged in.');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a non-negative integer, e.g. `--offset 0`.
  2. Clamp computed offsets: `Math.max(0, computedOffset)` before passing.
  3. Default unset variables: `${OFFSET:-0}` in shell.
  4. Catch ArgumentError and sanitize with Number.parseInt plus a >= 0 check before invoking.

Example fix

// before
opencli zhihu collection 83283292 --offset -10
// ArgumentError: --offset must be a non-negative integer
// after
const offset = Math.max(0, (page - 1) * limit);
opencli zhihu collection 83283292 --offset ${offset}
Defensive patterns

Strategy: validation

Validate before calling

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; }

Type guard

function isNonNegativeInt(v) { return Number.isInteger(Number(v)) && Number(v) >= 0; }

Try / catch

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; }

Prevention

When it happens

Trigger: Passing `--offset -1`, `--offset 1.5`, `--offset x`, or an empty value to `opencli zhihu collection`; pageOffset() applies validateNonNegativeInt to the raw option.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3bfd4c4c754d4b27. Report an issue: GitHub.