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` stays

View on GitHub (pinned to 9690622007)

Solutions

  1. Filter empty strings out of the paths array before calling: `paths.filter(p => p.trim().length > 0)`.
  2. Fix the upstream split that produced the empty entry (guard against trailing/duplicate delimiters).
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/c0b485c912db4c87. Report an issue: GitHub.