jackwener/OpenCLI · error · ArgumentError

juejin cursor must be a non-negative decimal integer

Error message

juejin cursor must be a non-negative decimal integer

What it means

requireCursor normalizes pagination cursors and throws an ArgumentError when a numeric cursor is not a non-negative safe integer. Negative numbers, floats, Infinity/NaN, and unsafe integers are all rejected, since Juejin article cursors are offsets/ids expressed as non-negative decimal integers.

Source

Thrown at clis/juejin/utils.js:59

        n = Number(raw);
    }
    else {
        throw new ArgumentError(`juejin ${label} must be a positive decimal integer`);
    }
    if (!Number.isSafeInteger(n) || n <= 0) {
        throw new ArgumentError(`juejin ${label} must be a positive integer`);
    }
    if (n > maxValue) {
        throw new ArgumentError(`juejin ${label} must be <= ${maxValue}`);
    }
    return n;
}

export function requireCursor(value) {
    const raw = value ?? '0';
    if (typeof raw === 'number') {
        if (Number.isSafeInteger(raw) && raw >= 0) return String(raw);
        throw new ArgumentError('juejin cursor must be a non-negative decimal integer');
    }
    if (typeof raw === 'string' && /^(0|[1-9]\d*)$/.test(raw)) {
        return raw;
    }
    throw new ArgumentError('juejin cursor must be a non-negative decimal integer');
}

/** Resolve a `--category` arg to the underlying numeric category id. */
export function resolveCategory(value) {
    if (value == null) return '';
    const raw = String(value).trim();
    if (!raw) return '';
    if (JUEJIN_ID.test(raw)) return raw;
    const slug = raw.toLowerCase();
    if (CATEGORY_ALIASES[slug]) return CATEGORY_ALIASES[slug];
    throw new ArgumentError(
        `juejin category "${value}" is not recognised`,
        `Use a category id (e.g. "${CATEGORY_ALIASES.backend}") or one of: ${Object.keys(CATEGORY_ALIASES).join(', ')}.`,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a valid non-negative integer cursor (e.g. --cursor 0 to start over).
  2. Clamp/round before calling: n = Math.max(0, Math.floor(n)).
  3. Use the next_cursor value from the previous response verbatim instead of doing arithmetic on cursors.
  4. For very large ids, pass them as strings matching /^(0|[1-9]\d*)$/ to avoid float precision loss.

Example fix

// before
const next = Number(cursor) - pageSize; // can go negative
// after
const next = Math.max(0, Number(cursor) - pageSize);
cli({ cursor: String(next) });
Defensive patterns

Strategy: type-guard

Validate before calling

function validNumberCursor(n){ return typeof n === 'number' && Number.isSafeInteger(n) && n >= 0; }
// if (!validNumberCursor(cursor)) cursor = 0;

Type guard

function isNonNegativeSafeInt(v){ return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0; }

Try / catch

try {
  cli({ cursor });
} catch (e) {
  if (/cursor must be a non-negative decimal integer/.test(e.message)) {
    cli({ cursor: '0' }); // restart pagination
  } else throw e;
}

Prevention

When it happens

Trigger: Passing --cursor -1, --cursor 1.5, --cursor 1e21, or a float to a command option that routes through requireCursor; programmatically passing a computed number that is negative or non-integer.

Common situations: Arithmetic on cursors producing negatives (cursor - pageSize when at the first page); JSON numbers parsed as floats; JavaScript precision loss converting a big cursor id to a float that is not a safe integer.

Related errors


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