can1357/oh-my-pi · error · ToolError
skill:// path does not exist: ${url}
Error message
skill:// path does not exist: ${url} What it means
For containRoot skills, resolveContainedPathSync must be able to resolve the target's real path; a "missing" status (dangling symlink or nonexistent file) throws this ToolError rather than handing a broken path to bash. This is the fail-closed counterpart of the containment check: unresolvable paths are rejected.
Source
Thrown at packages/coding-agent/src/tools/bash-skill-urls.ts:117
}
const 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 ToolError("Path traversal is not allowed in skill:// URLs");
}
// Agent Plugin skills (§4.1): the resource must canonically resolve within
// the plugin root. Fail closed: a dangling or unresolvable path is rejected
// rather than handed to bash, where writing through it could create the
// outside target. Symlinks may target other files inside the same package.
if (skill.containRoot) {
const contained = resolveContainedPathSync(skill.containRoot, resolvedPath);
if (contained.status === "outside") {
throw new ToolError(`skill:// path resolves outside the plugin root: ${url}`);
}
if (contained.status === "missing") {
throw new ToolError(`skill:// path does not exist: ${url}`);
}
return contained.realPath;
}
return resolvedPath;
}
/**
* Match a raw skill segment against registered skills using longest-prefix match.
* Handles colons in both skill names (namespacing) and suffixes (line ranges).
*
* For "superpowers:brainstorming:1-5" with skill "superpowers:brainstorming":
* -> skill = superpowers:brainstorming, suffix = "1-5"
* For "brainstorming" with skill "brainstorming":
* -> skill = brainstorming, suffix = undefined
*/
function matchSkillName(
rawSegment: string,View on GitHub (pinned to 9690622007)
Solutions
- List the skill directory to find the correct file name, then retry with the exact name.
- Check case sensitivity — file names must match exactly.
- If a symlink is dangling, restore its target or remove the link from the package.
- Reinstall/update the plugin if its files are missing from the installed copy.
Example fix
// before
resolveSkillUrlToPath("skill://my-skill/reference.md", skills);
// skill:// path does not exist
// after
resolveSkillUrlToPath("skill://my-skill/references/index.md", skills); Defensive patterns
Strategy: fallback
Validate before calling
import * as fs from "node:fs";
const target = /* baseDir + decoded relative path */;
try { fs.realpathSync(target); } catch { throw new Error(`skill file missing: ${target}`); } Try / catch
try {
return resolveSkillUrlToPath(url, skills);
} catch (e) {
if (e instanceof ToolError && e.message.includes("does not exist")) {
// fall back: list the skill directory and retry with an existing file
} else throw e;
} Prevention
- Enumerate actual skill files before referencing them instead of guessing names.
- Match file names exactly, watching case sensitivity.
- After plugin updates, refresh any cached file references.
- Check for dangling symlinks when packaging skills.
When it happens
Trigger: A skill:// URL like "skill://name/docs/missing.md" for a containRoot skill where the file does not exist, or where the final path component is a symlink whose target was deleted (dangling link).
Common situations: The model guesses a filename inside the skill that isn't there; the skill's docs changed between versions; a symlink target was removed after packaging; case-sensitivity mismatch (README.md vs readme.md) on case-sensitive filesystems.
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: ${path}
- Local file not found: ${url.href}
- File not found: ${resolvedPath}
- File not found: ${targetPath}
- Vault file not found: ${parsed.url}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a6f772bb8a4badef.
Report an issue: GitHub.