farion1231/cc-switch · error · anyhow::Error
SKILL_DIR_NOT_FOUND
SKILL_DIR_NOT_FOUND
Error message
{"code":"SKILL_DIR_NOT_FOUND","context":{"path":"{path}"},"suggestion":"checkRepoUrl"} What it means
Structured error from CC Switch's skill installer: after a successful repo download, resolve_skill_source_dir (src-tauri/src/services/skill.rs:2986-3019) failed to locate the skill. It tries (1) the exact relative path only if it is a directory containing SKILL.md, (2) a recursive search for a directory named after the install name that has SKILL.md, (3) the repo root if it has SKILL.md. None matched, so install() (line 843-852) emits code SKILL_DIR_NOT_FOUND with context.path set to the attempted path under the temp clone and suggestion 'checkRepoUrl'.
Source
Thrown at src-tauri/src/services/skill.rs:844
.map_err(|_| {
anyhow!(format_skill_error(
"DOWNLOAD_TIMEOUT",
&[
("owner", &repo.owner),
("name", &repo.name),
("timeout", "60")
],
Some("checkNetwork"),
))
})??;
let temp_dir = temp_guard.path();
repo_branch = used_branch;
// 复制到 SSOT
let source =
Self::resolve_skill_source_dir(temp_dir, &skill.directory).ok_or_else(|| {
let missing = temp_dir.join(&source_rel).display().to_string();
anyhow!(format_skill_error(
"SKILL_DIR_NOT_FOUND",
&[("path", &missing)],
Some("checkRepoUrl"),
))
})?;
let canonical_temp = temp_dir
.canonicalize()
.unwrap_or_else(|_| temp_dir.to_path_buf());
let canonical_source = source.canonicalize().map_err(|_| {
anyhow!(format_skill_error(
"SKILL_DIR_NOT_FOUND",
&[("path", &source.display().to_string())],
Some("checkRepoUrl"),
))
})?;
if !canonical_source.starts_with(&canonical_temp) || !canonical_source.is_dir() {
return Err(anyhow!(format_skill_error(View on GitHub (pinned to a2e22f3302)
Solutions
- Open the repo on GitHub at the reported path (context.path) and find where SKILL.md actually lives now
- Refresh the skills.sh listing and reinstall so the corrected directory is picked up
- If upstream is broken, install the skill from its canonical repo and report the stale index entry
Defensive patterns
Strategy: try-catch
Try / catch
try {
await install(skill);
} catch (e) {
if (isSkillError(e) && e.code === "SKILL_DIR_NOT_FOUND") {
// e.context.path shows the attempted path inside the temp clone; e.suggestion === "checkRepoUrl"
openOnGitHub(`${skill.repoOwner}/${skill.repoName}`, e.context.path);
refreshCatalogThenRetry(skill);
return;
}
throw e;
} Prevention
- Refresh the skills.sh index before installing older entries — upstream restructures are the top cause
- A directory without SKILL.md never matches; verify the skill really exists at the declared path on GitHub
- Report stale index entries upstream so the directory field gets corrected
When it happens
Trigger: The skills.sh index entry references a directory that was renamed/moved upstream; the declared branch's tree lacks the folder; the repo has a same-named directory WITHOUT a SKILL.md (an empty shell, which the resolver deliberately rejects); a wrapper repo whose inner skill is absent.
Common situations: Stale marketplace metadata after an upstream restructure; upstream deleted or relocated the skill; wrong repo/branch combination; the directory field only carries the skillId while the real content lives elsewhere (the resolver's fallbacks usually handle this — failure means even the fallbacks found nothing).
Related errors
- SKILL_DIRECTORY_CONFLICT
- INVALID_SKILL_DIRECTORY
- Skill 存储目录不能与 {app:?} 的 Skills 目录相同: {}
- DOWNLOAD_TIMEOUT
- Skill directory changed during install; please retry
AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16).
Data as JSON: /api/errors/3d65c7e497632e57.
Report an issue: GitHub.