can1357/oh-my-pi · error · ToolError
Skip must be a non-negative number
Error message
Skip must be a non-negative number
What it means
The `skip` option (number of leading matches to skip for pagination) must be a non-negative finite number. undefined/null are treated as 0, but negative values, non-numeric values, and NaN (e.g. from a non-numeric string converted via Number) are rejected.
Source
Thrown at packages/coding-agent/src/tools/grep.ts:967
params: SearchParams,
signal?: AbortSignal,
_onUpdate?: AgentToolUpdateCallback<GrepToolDetails>,
_toolContext?: AgentToolContext,
): Promise<AgentToolResult<GrepToolDetails>> {
const { pattern, path: rawPath, case: caseSensitive, gitignore, skip } = params;
return untilAborted(signal, async () => {
// Preserve the pattern verbatim — leading/trailing whitespace is
// meaningful in regexes (indentation anchors, trailing-space matches).
if (!pattern.trim()) {
throw new ToolError("Pattern must not be empty");
}
const normalizedPattern = pattern;
const normalizedSkip =
skip === undefined || skip === null ? 0 : Number.isFinite(skip) ? Math.floor(skip) : Number.NaN;
if (normalizedSkip < 0 || !Number.isFinite(normalizedSkip)) {
throw new ToolError("Skip must be a non-negative number");
}
const scopedPaths = toPathList(rawPath);
const effectivePaths = scopedPaths.length > 0 ? scopedPaths : ["."];
const rawEntries = await expandDelimitedPathEntries(effectivePaths, this.session.cwd);
const pathSpecs = await parsePathSpecs(rawEntries, this.session.cwd);
const materializedExternalPaths = new Map<string, string>();
const materializeExternalUrlForSearch = async (rawPath: string) => {
const target = parseReadUrlTarget(rawPath);
if (!target) return undefined;
const materialized = await materializeReadUrlToFile(
this.session,
{ path: target.path, raw: target.raw },
signal,
);
materializedExternalPaths.set(rawPath, materialized.path);
return { sourcePath: materialized.path, immutable: true };
};
const {View on GitHub (pinned to 9690622007)
Solutions
- Pass a non-negative integer (0 for the first page)
- Sanitize user input: const s = Math.max(0, Math.floor(Number(raw) || 0))
- Check the page calculation that produced the negative value (e.g. page 0 minus 1)
Example fix
// before
await grep({ pattern: "err", skip: (page - 1) * pageSize });
// after
const skip = Math.max(0, (page - 1) * pageSize);
await grep({ pattern: "err", skip }); Defensive patterns
Strategy: validation
Validate before calling
const skip = Math.max(0, Math.floor(Number(rawSkip) || 0));
if (!Number.isFinite(skip) || skip < 0) throw new Error("skip must be a non-negative number"); Type guard
const isNonNegativeFinite = (n: unknown): n is number => typeof n === "number" && Number.isFinite(n) && n >= 0;
Prevention
- Clamp pagination math with Math.max(0, ...)
- Coerce and validate string inputs with Number() before passing
When it happens
Trigger: grep with skip: -5, skip: "10" coerced to NaN, skip: Number("") (0 would pass but Number("abc") yields NaN), or skip: Infinity.
Common situations: Paginating results with an off-by-one negative page index; parsing a page param from a query string that is empty or non-numeric; passing a string instead of a number.
Understand the failure class
Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.
Related errors
- Invalid ACP session cursor: ${cursor}
- Invalid RPC message cursor
- RPC message page limit must be between 1 and ${MAX_RPC_MESSA
- skip must be a non-negative number
- Pattern must not be empty
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/2d7ed40340ec99db.
Report an issue: GitHub.