can1357/oh-my-pi · error
File not found: ${resolvedPath}
Error message
File not found: ${resolvedPath} What it means
This error comes from the skill:// internal-URL protocol handler. When a skill belongs to an Agent Plugin with a containment root (`skill.containRoot`), the requested path is canonically resolved inside that root via `resolveContainedPath`. If the resolution reports `missing`, meaning the path (after resolving symlinks) does not exist within the plugin root, the handler fails closed with 'File not found'.
Source
Thrown at packages/coding-agent/src/internal-urls/skill-protocol.ts:89
const relativePath = decodeURIComponent(urlPath.slice(1));
validateRelativePath(relativePath);
targetPath = path.join(skill.baseDir, relativePath);
const resolvedPath = path.resolve(targetPath);
const resolvedBaseDir = path.resolve(skill.baseDir);
if (!resolvedPath.startsWith(resolvedBaseDir + path.sep) && resolvedPath !== resolvedBaseDir) {
throw new Error("Path traversal is not allowed");
}
// Agent Plugin skills (§4.1): the resource must canonically resolve
// within the plugin root; a dangling or unresolvable path fails closed.
// Symlinks may target other files inside the same package.
if (skill.containRoot) {
const contained = await resolveContainedPath(skill.containRoot, resolvedPath);
if (contained.status === "outside") {
throw new Error(`skill:// path resolves outside the plugin root: ${url.href}`);
}
if (contained.status === "missing") {
throw new Error(`File not found: ${resolvedPath}`);
}
targetPath = contained.realPath;
}
} else {
targetPath = context?.pathOnly === true ? skill.baseDir : skill.filePath;
}
let stats: fsTypes.Stats;
try {
stats = await fs.stat(targetPath);
} catch (error) {
if (isEnoent(error)) {
throw new Error(`File not found: ${targetPath}`);
}
throw error;
}
if (stats.isDirectory()) {View on GitHub (pinned to 9690622007)
Solutions
- Verify the path in the skill:// URL exists inside the plugin root (run `ls` on the plugin's baseDir/containRoot).
- Check the plugin version — the file may have been renamed or removed; update the URL or the plugin.
- If the file is a symlink, confirm its target resolves inside the plugin root and actually exists.
- Read the SKILL.md itself (skill://<name> with no path) to discover the correct bundled file names.
Example fix
// before
const res = await handler.resolve(parseInternalUrl("skill://deploy/scripts/run.sh"));
// after
const res = await handler.resolve(parseInternalUrl("skill://deploy/scripts/run-remote.sh")); // path corrected to match bundled file Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs/promises";
import * as path from "node:path";
// Before resolving, confirm the relative path exists under the skill's baseDir.
const rel = "scripts/run-remote.sh";
const abs = path.resolve(skill.baseDir, rel);
try {
await fs.stat(abs); // throws ENOENT if missing
} catch {
throw new Error(`Refusing skill:// URL: ${rel} does not exist in skill ${skill.name}`);
} Try / catch
try {
const resource = await handler.resolve(url);
} catch (err) {
if (err instanceof Error && err.message.startsWith("File not found:")) {
// fall back to reading the SKILL.md index
return handler.resolve(parseInternalUrl(`skill://${skillName}`));
}
throw err;
} Prevention
- List the plugin root's real file names before building skill://<name>/<path> URLs.
- Read skill://<name> (SKILL.md) first to discover bundled resource paths.
- Re-sync/reinstall plugins after version changes so referenced files exist.
- Never hand-write paths from memory — verify against the plugin directory.
When it happens
Trigger: Calling `SkillProtocolHandler.resolve()` on a `skill://<name>/<path>` URL where the skill has a `containRoot` and `resolveContainedPath(skill.containRoot, resolvedPath)` returns status `"missing"` — i.e. the referenced relative path does not exist (or is an unresolvable/dangling symlink) inside the plugin root.
Common situations: Referencing an auxiliary file (script, template, data file) alongside a plugin skill's SKILL.md that was renamed, moved, or never shipped; typos in the path portion of skill:// URLs; dangling symlinks inside the plugin package; tooling or an agent hallucinating a path that exists in a different plugin version.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- File not found: ${targetPath}
- File not found: ${path}
- Local file not found: ${url.href}
- skill:// URL must resolve to a file or directory: ${url.href
- Vault file not found: ${parsed.url}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b502af2fe6d4f8bb.
Report an issue: GitHub.