can1357/oh-my-pi · error · ToolError

Path not found: ${missingPaths.join(", ")}; list each target

Error message

Path not found: ${missingPaths.join(", ")}; list each target in the semicolon-delimited `path`${archiveHint}

What it means

All paths supplied to grep were missing on disk (and none were searchable or virtual resources), so the search cannot proceed. The message lists every missing path and reminds you that multiple targets go in the semicolon-delimited `path` field; if archive members were also unsearchable, they are appended as a hint.

Source

Thrown at packages/coding-agent/src/tools/grep.ts:1118

						: physicalScopePath;
				} else {
					searchPath = this.session.cwd;
					scopePath = internalResolution.virtualScopePath ?? ".";
					globFilter = undefined;
					isDirectory = false;
					multiTargets = undefined;
					exactFilePaths = undefined;
					missingPaths = [];
				}
				if (
					missingPaths.length > 0 &&
					missingPaths.length === searchablePaths.length &&
					virtualResources.length === 0
				) {
					const archiveHint =
						archiveUnreadable.length > 0
							? ` (archive members were not searchable: ${archiveUnreadable.join(", ")})`
							: "";
					throw new ToolError(
						`Path not found: ${missingPaths.join(", ")}; list each target in the semicolon-delimited \`path\`${archiveHint}`,
					);
				}
				const baseDisplayMode = resolveFileDisplayMode(this.session);

				const effectiveOutputMode = GrepOutputMode.Content;
				const isMultiScope =
					isDirectory ||
					Boolean(exactFilePaths) ||
					Boolean(multiTargets) ||
					(virtualResources.length > 0 && (virtualResources.length > 1 || searchablePaths.length > 0));
				const perFileMatchCap = isMultiScope ? MULTI_FILE_PER_FILE_MATCHES : SINGLE_FILE_MATCHES;
				// Range filtering happens in JS after the native fetch, so out-of-range
				// matches consume fetch budget. Widen the per-file budget just enough
				// that filtering can still yield `perFileMatchCap` in-range hits, and
				// scale the global safety ceiling by the same amplification so ranged
				// searches keep the baseline file coverage while staying finite.

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix each listed path — verify with ls/read relative to the session cwd
  2. Widen the search: omit `path` (defaults to ".") or pass a directory that exists
  3. If archive members appear in the hint, read them via `read <archive>:<member>` to confirm member names

Example fix

// before
await grep({ pattern: "init", path: "src/old_config.ts" });
// after
await grep({ pattern: "init", path: "src/config.ts" });
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs";
const missing = paths.filter((p) => !fs.existsSync(p));
if (missing.length === paths.length) throw new Error(`All grep paths missing: ${missing.join(", ")}`);

Try / catch

try {
  await grep({ pattern, path });
} catch (err) {
  if (err instanceof ToolError && err.message.startsWith("Path not found:")) {
    // fall back to a wider search or log the listed missing paths
  } else throw err;
}

Prevention

When it happens

Trigger: grep whose entire semicolon-delimited `path` list contains paths that stat as non-existent, e.g. path: "old/dir;renamed/file.ts" after a refactor.

Common situations: Files deleted or renamed since the command was written; wrong working directory; case-sensitivity mismatches on Linux; paths copied from another machine.

Related errors


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