ultraworkers/claw-code · error · std::io::Error
skill source '{}' not found: {e}
Error message
skill source '{}' not found: {e} What it means
`resolve_skill_install_source` (commands/src/lib.rs:3863) builds a candidate from the `/skills install <source>` argument — absolute as-is, otherwise joined onto the handler's `cwd` (the process working directory, not your shell's notion of 'here') — then `fs::canonicalize` fails. The error re-wraps the OS error kind (NotFound, PermissionDenied, etc.) with the candidate path in the message.
Source
Thrown at rust/crates/commands/src/lib.rs:3863
}
if let Some(home) = env::var_os("HOME") {
return Ok(PathBuf::from(home).join(".claw").join("skills"));
}
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"unable to resolve a skills install root; set CLAW_CONFIG_HOME or HOME",
))
}
fn resolve_skill_install_source(source: &str, cwd: &Path) -> std::io::Result<SkillInstallSource> {
let candidate = PathBuf::from(source);
let source = if candidate.is_absolute() {
candidate
} else {
cwd.join(candidate)
};
let source = fs::canonicalize(&source).map_err(|e| {
std::io::Error::new(
e.kind(),
format!("skill source '{}' not found: {e}", source.display()),
)
})?;
if source.is_dir() {
let prompt_path = source.join("SKILL.md");
if !prompt_path.is_file() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"skill directory '{}' must contain SKILL.md",
source.display()
),
));
}
return Ok(SkillInstallSource::Directory {
root: source,View on GitHub (pinned to 08106b0c37)
Solutions
- Pass an absolute path to `/skills install`.
- Verify the path exists from the same cwd the claw process was started in (`pwd; ls <source>`).
- Check the underlying kind in the message — PermissionDenied means a parent dir traversal problem, not a typo.
Example fix
# before /skills install my-skill # skill source 'my-skill' not found ... # after /skills install /home/me/skills/my-skill
Defensive patterns
Strategy: validation
Validate before calling
// mirror resolve_skill_install_source's resolution before calling install
let candidate = Path::new(source);
let candidate = if candidate.is_absolute() { candidate.to_path_buf() } else { cwd.join(candidate) };
if !candidate.exists() { /* fix the path, don't call install */ } Try / catch
if let Err(e) = install_skill(source, cwd) {
if e.to_string().contains("skill source") && e.to_string().contains("not found") {
// re-resolve as absolute path and retry
}
} Prevention
- Prefer absolute paths for /skills install
- Relative paths resolve against the claw process cwd — verify with pwd
- Canonicalize or at least `ls` the path from the same cwd first
When it happens
Trigger: Passing a relative skill path to `/skills install` while the claw process runs with a different cwd; a typo in the path; the source being deleted between typing and executing; parent directory unreadable (canonicalize returns PermissionDenied).
Common situations: Installing from a path that is relative to the directory where claw was launched, not the directory the user thinks they are in; paths copied with a trailing `.` or wrong quoting; network-mounted homes where canonicalize can fail transiently.
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
- unable to resolve a skills install root; set CLAW_CONFIG_HOM
- skill directory '{}' must contain SKILL.md
- skill source '{}' must be a directory with SKILL.md or a mar
- unable to derive an installable invocation name from '{}'
- PowerShell executable not found (expected `pwsh` or `powersh
AI-assisted analysis of ultraworkers/claw-code@08106b0c37 (2026-08-18).
Data as JSON: /api/errors/27e6449f659e4c10.
Report an issue: GitHub.