can1357/oh-my-pi · error · ToolError
Path not found: ${scopePath}
Error message
Path not found: ${scopePath} What it means
When custom operations (customOps.glob) are configured, execute() checks each search target's existence via customOps.exists before scanning. If the path does not exist and a single path was requested, a clean 'Path not found' ToolError is thrown instead of an empty result or raw fs error.
Source
Thrown at packages/coding-agent/src/tools/glob.ts:386
.text(truncation.content)
.limits({ resultLimit: limitMeta.resultLimit?.reached });
if (truncation.truncated) {
resultBuilder.truncation(truncation, { direction: "head" });
}
return resultBuilder.done();
};
// Walk each user path as its own root and run the globs concurrently.
// Collapsing multiple paths to a shared base would force the walker to
// traverse and stat every unrelated sibling under that ancestor; per-path
// roots keep each scan bounded to exactly what the user asked for.
if (this.#customOps?.glob) {
const customOps = this.#customOps;
const perTarget = await Promise.all(
targets.map(async target => {
if (!(await customOps.exists(target.searchPath))) {
if (isSingle) throw new ToolError(`Path not found: ${scopePath}`);
return [] as string[];
}
if (!target.hasGlob && customOps.stat) {
const stat = await customOps.stat(target.searchPath);
if (stat.isFile()) return [formatScopePath(target.searchPath)];
}
const results = await customOps.glob(target.globPattern, target.searchPath, {
ignore: ["**/node_modules/**", "**/.git/**"],
limit: effectiveLimit,
});
return results.map(matchPath => formatMatchPath(matchPath, target.searchPath));
}),
);
const seen = new Set<string>();
const merged: string[] = [];
for (const group of perTarget) {
for (const entry of group) {
if (seen.has(entry)) continue;View on GitHub (pinned to 9690622007)
Solutions
- Verify the path exists before calling (fs stat / customOps.exists)
- Fix the path spelling and ensure it is resolved against the intended cwd
- For multiple targets, note non-existent ones are skipped (empty results) rather than throwing — only single-target calls throw
Example fix
// before
await globTool.execute({ pattern: "*.ts", path: "src/typos" })
// after
if (await fs.stat("src/tools").catch(() => null)) {
await globTool.execute({ pattern: "*.ts", path: "src/tools" })
} Defensive patterns
Strategy: validation
Validate before calling
const st = await fs.stat(p).catch(() => null);
if (!st) throw new Error(`Target path does not exist: ${p}`);
await globTool.execute({ pattern, path: p }); Type guard
async function pathExists(p: string): Promise<boolean> {
return (await fs.stat(p).catch(() => null)) !== null;
} Try / catch
try {
return await globTool.execute({ pattern, path });
} catch (err) {
if (err instanceof ToolError && err.message.startsWith("Path not found:")) {
return []; // treat as no matches for the missing target
}
throw err;
} Prevention
- Stat the target before globbing
- Re-verify paths held in long-lived state still exist
- Use multi-target calls if you want missing paths skipped rather than fatal
When it happens
Trigger: Calling the glob tool with a single non-existent path while customOps is active (e.g. virtual/sandboxed filesystem ops); typos in the directory path; deleted or moved directories.
Common situations: Path computed from stale session state; relative paths resolved against the wrong cwd; referencing a file that was deleted by a prior tool call.
Related errors
- Path not found: ${absolutePath}
- Path is not a directory: ${target.searchPath}
- Path '${localReadPath}' not found
- unknown filetype: {ft_debug}
- Is a directory
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/2cdc374112a4dab8.
Report an issue: GitHub.