can1357/oh-my-pi · error · ToolError
Search scope entries must be non-empty paths or globs
Error message
Search scope entries must be non-empty paths or globs
What it means
resolveToolSearchScope validates every raw scope entry before use and throws a ToolError if any entry is an empty string after normalization. Search scope entries must name a real path or glob; empty strings indicate a malformed call.
Source
Thrown at packages/coding-agent/src/tools/path-utils.ts:1498
multiTargets?: ResolvedSearchTarget[];
exactFilePaths?: string[];
missingPaths: string[];
immutableSourcePaths: Set<string>;
}
/**
* Shared path-input pipeline for `search`, `ast_grep`, and `ast_edit`:
* 1. normalize + reject empty paths,
* 2. resolve internal URLs through {@link InternalUrlRouter} to backing files,
* 3. partition existing vs missing when multiple paths are supplied,
* 4. derive a single search base path / glob, or a multi-target list,
* 5. stat the resolved base path so callers can branch on directory vs file scope.
*/
export async function resolveToolSearchScope(opts: ToolScopeOptions): Promise<ToolScopeResolution> {
const { rawPaths: inputs, cwd, internalUrlAction } = opts;
const normalizedRawPaths = inputs.map(normalizePathLikeInput);
if (normalizedRawPaths.some(rawPath => rawPath.length === 0)) {
throw new ToolError("Search scope entries must be non-empty paths or globs");
}
const rawPaths = await expandDelimitedPathEntries(normalizedRawPaths, cwd);
if (rawPaths.some(rawPath => rawPath.length === 0)) {
throw new ToolError("Search scope entries must be non-empty paths or globs");
}
// Strict external-URL schemes. `file://` is intentionally absent: it has
// local-path semantics (expandPath strips it downstream), so it flows through
// the ordinary filesystem pipeline instead of the external-URL resolver.
const strictExternalUrlRe = /^(?:https?|ftp|ws|wss):\/\//i;
const internalRouter = InternalUrlRouter.instance();
const resolvedPathInputs: string[] = [];
const immutableSourcePaths = new Set<string>();
for (const rawPath of rawPaths) {
let externalUrl = strictExternalUrlRe.test(rawPath);
if (!externalUrl && isReadableUrlPath(rawPath) && !hasGlobPathChars(rawPath)) {
// Fuzzy spelling the read parser accepts (`www.host/…`, collapsed
// `https:/host/…`). An existing local path wins over URL
// interpretation so a directory literally named `www.foo` staysView on GitHub (pinned to 9690622007)
Solutions
- Filter empty strings out of the paths array before calling: `paths.filter(p => p.trim().length > 0)`.
- Fix the upstream split that produced the empty entry (guard against trailing/duplicate delimiters).
- If no scope is intended, omit the entry or pass the cwd explicitly instead of an empty string.
Example fix
// before
search({ paths: input.split(",") }) // "src,,lib" -> ["src","","lib"]
// after
search({ paths: input.split(",").map(s => s.trim()).filter(Boolean) }) Defensive patterns
Strategy: validation
Validate before calling
const paths = rawInput.split(",").map(s => s.trim()).filter(Boolean);
if (paths.length === 0) throw new Error("At least one non-empty search path is required"); Type guard
const hasEmptyEntry = (paths) => !Array.isArray(paths) || paths.some(p => typeof p !== "string" || p.trim().length === 0);
Try / catch
try { await resolveToolSearchScope({ rawPaths, cwd, internalUrlAction: "search" }); }
catch (e) { if (String(e.message).includes("non-empty")) { rawPaths = rawPaths.filter(Boolean); /* retry */ } else throw e; } Prevention
- Always trim + filter path arrays before passing to search tools.
- Guard delimiter-based splits against trailing/duplicate separators.
- Validate user/config-supplied path lists at the boundary.
When it happens
Trigger: Calling resolveToolSearchScope (backing search/ast_grep/ast_edit) with `rawPaths` containing `""` — e.g. an empty element from splitting a path list on a delimiter, or an unset variable interpolated into the paths array.
Common situations: Splitting a comma/space-separated path string that has a trailing or double delimiter (`src,,lib`); an environment variable or config field that is empty being pushed into the paths array; agent emitting `paths: [""]`.
Related errors
- Managed skill "${name}" needs a non-empty description.
- Managed skill "${name}" needs a non-empty body.
- Snippet file not found: ${resolved}
- ACP cwd must be absolute: ${cwd}
- Security knowledge base is not a file: ${input}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c0b485c912db4c87.
Report an issue: GitHub.