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` pagination offset must be a finite, non-negative number. The tool floors the value and rejects NaN, ±Infinity, and negative numbers, since an invalid skip would corrupt result pagination for the underlying search.
Source
Thrown at packages/coding-agent/src/tools/ast-grep.ts:206
constructor(private readonly session: ToolSession) {}
async execute(
_toolCallId: string,
params: typeof astGrepSchema.infer,
signal?: AbortSignal,
_onUpdate?: AgentToolUpdateCallback<AstGrepToolDetails>,
_context?: AgentToolContext,
): Promise<AgentToolResult<AstGrepToolDetails>> {
return untilAborted(signal, async () => {
const pattern = params.pat.trim();
if (pattern.length === 0) {
throw new ToolError("`pat` must be a non-empty pattern");
}
const patterns = [pattern];
const skip = params.skip === undefined ? 0 : Math.floor(params.skip);
if (!Number.isFinite(skip) || skip < 0) {
throw new ToolError("skip must be a non-negative number");
}
const scopedPaths = toPathList(params.path);
const rawPaths = scopedPaths.length > 0 ? scopedPaths : ["."];
const scope = await resolveToolSearchScope({
rawPaths,
cwd: this.session.cwd,
internalUrlAction: "search",
settings: this.session.settings,
signal,
sessionFile: this.session.getSessionFile() ?? undefined,
localProtocolOptions: this.session.localProtocolOptions,
skills: this.session.skills,
resolveExternalUrl: async rawPath => {
const target = parseReadUrlTarget(rawPath);
if (!target) return undefined;
const materialized = await materializeReadUrlToFile(
this.session,
{ path: target.path, raw: target.raw },View on GitHub (pinned to 9690622007)
Solutions
- Pass a non-negative integer for `skip` (or omit it to start at 0).
- Clamp the offset: skip = Math.max(0, Math.floor(Number(rawSkip) || 0)).
- Reject non-finite values at the caller boundary before invoking the tool.
Example fix
// before
await tool.execute({ pat, skip: page * -10 }, ctx);
// after
const skip = Math.max(0, Math.floor(page * 10));
await tool.execute({ pat, skip }, ctx); Defensive patterns
Strategy: validation
Validate before calling
const skip = params.skip === undefined ? 0 : Math.floor(params.skip);
if (!Number.isFinite(skip) || skip < 0) throw new Error("skip must be a non-negative finite number"); Type guard
function isValidSkip(v: unknown): v is number {
return typeof v === "number" && Number.isFinite(v) && v >= 0;
} Try / catch
try {
await tool.execute({ pat, skip }, ctx);
} catch (e) {
if (e instanceof ToolError && e.message.includes("skip must be")) {
// retry once with skip omitted (defaults to 0) or clamped value
} else throw e;
} Prevention
- Clamp computed offsets: Math.max(0, Math.floor(x)).
- Never derive skip from possibly-NaN arithmetic without a Number.isFinite check.
- Omit `skip` entirely on the first page.
When it happens
Trigger: Calling AstGrepTool.execute with params.skip set to -1, NaN, Infinity, or -Infinity. (undefined is allowed and defaults to 0.)
Common situations: A model emits an out-of-range or symbolic value for `skip`; upstream code computes an offset that underflows (e.g. page * pageSize with a negative page); JSON parsing yields NaN from "NaN" input.
Related errors
- objective is required when op=create
- token_budget must be a positive integer when provided
- Invalid ACP session cursor: ${cursor}
- Invalid RPC message cursor
- RPC message page limit must be between 1 and ${MAX_RPC_MESSA
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3851efb9712e54c9.
Report an issue: GitHub.