zeroclaw-labs/zeroclaw · error · anyhow::Error
skill '{$skill}' not found in {$url}. Available skills: {$av
Error message
skill '{$skill}' not found in {$url}.
Available skills: {$available} What it means
The requested skill name has no matching directory in the catalog's skills/ root, and the catalog does contain other skills — the message lists them comma-separated (from list_contained_catalog_skill_names, sorted) so the correct names can be picked immediately. Names are matched as literal directory names: case and separators matter.
Source
Thrown at crates/zeroclaw-runtime/src/skills/mod.rs:2448
if !skills_root.is_dir() {
anyhow::bail!(crate::i18n::get_required_cli_string_with_args(
"cli-skills-install-skill-not-in-catalog-empty",
&[("skill", skill_name), ("url", url)]
));
}
let skill_dir = skills_root.join(skill_name);
let entry_meta = match std::fs::symlink_metadata(&skill_dir) {
Ok(metadata) => metadata,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
let available = list_contained_catalog_skill_names(&skills_root);
if available.is_empty() {
anyhow::bail!(crate::i18n::get_required_cli_string_with_args(
"cli-skills-install-skill-not-in-catalog-empty",
&[("skill", skill_name), ("url", url)]
));
}
anyhow::bail!(crate::i18n::get_required_cli_string_with_args(
"cli-skills-install-skill-not-in-catalog",
&[
("skill", skill_name),
("url", url),
("available", &available.join(", ")),
]
));
}
Err(err) => {
return Err(err).with_context(|| {
format!(
"failed to read metadata for selected catalog skill {}",
skill_dir.display()
)
});
}
};
if entry_meta.file_type().is_symlink() {View on GitHub (pinned to 88bb9c8533)
Solutions
- Pick the exact name from the 'Available skills' list embedded in the error message
- Mind case and separators — the name must equal the directory name under skills/ exactly
- If you maintain the catalog, add a skills/<name>/ directory for the missing skill
Example fix
# before zeroclaw skills install --url <catalog-url> --skill web-scraper # error: ... Available skills: web_scraper, web-scraper-v2 # after zeroclaw skills install --url <catalog-url> --skill web-scraper-v2
Defensive patterns
Strategy: try-catch
Try / catch
match install_git_catalog_skill_source(url, skill, &skills_path, false, &ws) {
Err(e) => {
let msg = e.to_string();
if let Some(idx) = msg.find("Available skills: ") {
let names: Vec<&str> = msg[idx + "Available skills: ".len()..].split(", ").collect();
// offer the user a pick from `names`; retry with the exact choice
}
Err(e)
}
r => r,
} Prevention
- Parse the 'Available skills:' suffix to build an interactive picker instead of failing flat
- Match names exactly — case and separator sensitive, they are literal directory names
- Pin skill names in config to catalog releases you have verified
When it happens
Trigger: Typo or case mismatch in the skill name; the skill was renamed upstream; requesting 'foo' when the catalog ships 'foo-v2'; hyphen vs underscore confusion (my_skill vs my-skill).
Common situations: Version-suffixed names after a catalog refactor; stale docs or tutorials referencing old names; keyboard autocorrect altering names.
Related errors
- skill '{$skill}' not found in {$url}: no skills/ directory,
- skill '{source}' not found in the registry. Available skills
- skill '{skill_name}' not found in registry '{registry_name}'
- skill '{source}' not found in the registry and no skills are
- skill '{skill_name}' not found in registry '{registry_name}'
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0df88e940d08edd3.
Report an issue: GitHub.