{"record":{"id":"c22f8bef2ffb2d50","repo":"can1357/oh-my-pi","slug":"limit-must-be-a-positive-number-c22f8b","errorCode":null,"errorMessage":"Limit must be a positive number","messagePattern":"Limit must be a positive number","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/glob.ts","lineNumber":301,"sourceCode":"\t\t\t\t\t\t\tconst parsed = parseFindPattern(effectivePatterns[0] ?? \".\");\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tsearchPath: resolveToCwd(parsed.basePath, this.session.cwd),\n\t\t\t\t\t\t\t\tglobPattern: parsed.globPattern,\n\t\t\t\t\t\t\t\thasGlob: parsed.hasGlob,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t})(),\n\t\t\t\t\t];\n\t\t\tconst scopePath = multiPattern?.scopePath ?? formatScopePath(targets[0].searchPath);\n\n\t\t\tfor (const target of targets) {\n\t\t\t\tif (target.searchPath === \"/\") {\n\t\t\t\t\tthrow new ToolError(\"Searching from root directory '/' is not allowed\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst requestedLimit = limit ?? DEFAULT_LIMIT;\n\t\t\tif (!Number.isFinite(requestedLimit) || requestedLimit <= 0) {\n\t\t\t\tthrow new ToolError(\"Limit must be a positive number\");\n\t\t\t}\n\t\t\tconst effectiveLimit = Math.min(MAX_LIMIT, Math.max(1, Math.floor(requestedLimit)));\n\t\t\tconst includeHidden = hidden ?? true;\n\t\t\tconst useGitignore = gitignore ?? true;\n\t\t\tconst timeoutMs = this.#timeoutMs;\n\t\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\t\tconst combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;\n\t\t\tconst formatMatchPath = (matchPath: string, base: string, fileType?: natives.FileType): string => {\n\t\t\t\tconst hadTrailingSlash = matchPath.endsWith(\"/\") || matchPath.endsWith(\"\\\\\");\n\t\t\t\tconst absolutePath = path.isAbsolute(matchPath) ? matchPath : path.resolve(base, matchPath);\n\t\t\t\treturn formatPathRelativeToCwd(absolutePath, this.session.cwd, {\n\t\t\t\t\ttrailingSlash: fileType === natives.FileType.Dir || hadTrailingSlash,\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst missingPathsNote =\n\t\t\t\tmissingPaths.length > 0 ? `Skipped missing paths: ${missingPaths.join(\", \")}` : undefined;\n","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/glob.ts#L283-L319","documentation":"The glob tool validates the caller-supplied limit before scanning. It must be a finite number greater than 0; the internal DEFAULT_LIMIT is used only when limit is omitted, not when it is explicitly null/0/negative/NaN.","triggerScenarios":"Calling execute() with limit: 0, a negative number, NaN, or Infinity (limit ?? DEFAULT_LIMIT does not replace an explicitly provided invalid value — only undefined/null).","commonSituations":"Computing a limit from user input without validation; propagating a NaN from a failed parseInt; JSON configs where 'limit: 0' means 'unlimited' to the caller but is rejected here.","solutions":["Pass a positive integer (e.g. limit: 50) or omit limit entirely to use the default","Clamp/validate user-supplied limits before calling: Number.isFinite(n) && n > 0","Replace NaN results from parsing with a sane default"],"exampleFix":"// before\nconst limit = Number(userInput); // NaN or 0 possible\nawait globTool.execute({ pattern, path, limit })\n// after\nconst parsed = Number(userInput);\nconst limit = Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\nawait globTool.execute({ pattern, path, limit })","handlingStrategy":"validation","validationCode":"function sanitizeLimit(n: number | undefined): number | undefined {\n  if (n === undefined) return undefined;\n  if (!Number.isFinite(n) || n <= 0) return undefined; // fall back to default\n  return Math.floor(n);\n}\nconst limit = sanitizeLimit(userLimit);","typeGuard":"function isValidLimit(n: unknown): n is number {\n  return typeof n === \"number\" && Number.isFinite(n) && n > 0;\n}","tryCatchPattern":"try {\n  return await globTool.execute({ pattern, path, limit });\n} catch (err) {\n  if (err instanceof ToolError && err.message === \"Limit must be a positive number\") {\n    return await globTool.execute({ pattern, path }); // default limit\n  }\n  throw err;\n}","preventionTips":["Omit limit instead of passing 0/null when you want the default","Clamp parsed user input: Math.max(1, Math.floor(Number(x) || default))","Never propagate parseInt output without Number.isNaN check"],"tags":["validation","parameters","glob-tool"],"backgroundTag":"invalid-parameter-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}