jackwener/OpenCLI · error · ArgumentError
targetCount must be a positive integer, got ${JSON.stringify
Error message
targetCount must be a positive integer, got ${JSON.stringify(targetCount)} What it means
buildScrollUntilJs validates that targetCount is a safe integer >= 1 before generating its scroll-until-enough browser IIFE, throwing this ArgumentError immediately otherwise. The parameter sets how many visible note rows to scroll until, so an invalid value would produce broken injected JS. This is a synchronous, fail-fast argument validation error at JS build time, not a page/automation failure.
Source
Thrown at clis/xiaohongshu/search.js:541
/**
* Build a "scroll until enough or plateaued" IIFE used in place of a fixed
* `autoScroll({ times: N })`. Xiaohongshu's search results page lazy-loads
* ~5-7 notes per scroll, so the previous `times: 2` capped extraction at
* ~13 items regardless of `--limit` (see #1471). This helper drives scrolls
* dynamically:
*
* - count visible `section.note-item` rows (excluding related-search
* `.query-note-item` rows)
* - if count >= targetCount → break (got enough)
* - if two consecutive scrolls add no new rows → break (DOM plateaued,
* no more lazy-load available)
* - hard cap at `maxScrolls` iterations (default 15) to bound runtime
*
* Exported so the rednote adapter (same DOM shape) can reuse it.
*/
export function buildScrollUntilJs(targetCount, maxScrolls = 15) {
if (!Number.isSafeInteger(targetCount) || targetCount < 1) {
throw new ArgumentError(`targetCount must be a positive integer, got ${JSON.stringify(targetCount)}`);
}
if (!Number.isSafeInteger(maxScrolls) || maxScrolls < 1) {
throw new ArgumentError(`maxScrolls must be a positive integer, got ${JSON.stringify(maxScrolls)}`);
}
return `
(async () => {
const isVisibleNote = (el) => {
if (el.classList.contains('query-note-item')) return false;
const rect = el.getBoundingClientRect();
if (rect.width <= 0 || rect.height <= 0) return false;
const style = getComputedStyle(el);
return style.display !== 'none' && style.visibility !== 'hidden';
};
// Note containers: legacy \`section.note-item\` first, fallback to
// any \`<section>\` that wraps a search-result/explore note link
// (#1506 reports the class being dropped on some xhs renders).
const collectNoteCards = () => {
const classMatches = document.querySelectorAll('section.note-item');View on GitHub (pinned to 49907e53dc)
Solutions
- Pass a positive safe integer, e.g. buildScrollUntilJs(50).
- If the value comes from user input, parse and validate it: Number.isSafeInteger(Number.parseInt(raw, 10)).
- Coerce with Math.max(1, Math.trunc(n)) after confirming the value is finite.
- Check upstream callers to find where undefined/null leaked into the argument.
Example fix
// before
const js = buildScrollUntilJs(process.env.LIMIT);
// after
const limit = Number.parseInt(process.env.LIMIT ?? '20', 10);
if (!Number.isSafeInteger(limit) || limit < 1) {
throw new Error(`invalid LIMIT: ${process.env.LIMIT}`);
}
const js = buildScrollUntilJs(limit); Defensive patterns
Strategy: validation
Validate before calling
function assertPositiveInt(v, name) {
if (!Number.isSafeInteger(v) || v < 1) {
throw new TypeError(`${name} must be a positive safe integer, got ${JSON.stringify(v)}`);
}
}
assertPositiveInt(targetCount, 'targetCount'); Type guard
const isPositiveInt = (v) => Number.isSafeInteger(v) && v >= 1;
Prevention
- Parse CLI/config numbers with Number.parseInt and validate before calling.
- Never pass raw strings or undefined into buildScrollUntilJs.
- Default missing values explicitly (limit ?? 20) after validation.
- Write a unit test covering 0, NaN, Infinity, and string inputs.
- Use Math.trunc + isSafeInteger checks when deriving limits dynamically.
When it happens
Trigger: Calling buildScrollUntilJs(targetCount) directly (or the rednote adapter reusing it) with 0, a negative number, a non-number (string, undefined, NaN, Infinity), or a float.
Common situations: Passing an unparsed CLI --limit string; forgetting a default so the argument is undefined; a config object returning null/NaN; computing the limit from a parse that failed silently.
Related errors
- maxScrolls must be a positive integer, got ${JSON.stringify(
- maxRounds must be a positive integer, got ${JSON.stringify(m
- budgetMs must be a positive number, got ${JSON.stringify(bud
- step must be a non-negative number, got ${JSON.stringify(ste
- Omni Reference accepts exactly one local image
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/b85f780d0f252d6f.
Report an issue: GitHub.