farion1231/cc-switch · error · anyhow::Error
SKILL_DIR_NOT_FOUND
SKILL_DIR_NOT_FOUND
Error message
SKILL_DIR_NOT_FOUND
What it means
After a successful download, install() locates the skill inside the temp clone via resolve_skill_source_dir(temp_dir, &skill.directory); when it returns None, the join of the expected relative path is formatted into SKILL_DIR_NOT_FOUND (context.path, suggestion 'checkRepoUrl'). This means the repository downloaded fine but the declared subdirectory does not exist at that path — the catalog's directory field points at something the repo layout does not contain (renamed upstream, branch mismatch, case-sensitive path typo, or nested layout moved).
Solutions
- Open the repo at the URL in the error and find where the skill folder actually lives now, then install using the updated catalog/discovery entry.
- If the skill only exists on a specific branch, ensure repo_branch in the skill metadata matches it before installing.
- Match path casing exactly (Linux is case-sensitive); re-fetch the skill list so metadata is current.
Example fix
# before directory field: "python/PDF-Tools" # repo actually has python/pdf-tools install(...) # -> SKILL_DIR_NOT_FOUND path=/tmp/xyz/python/PDF-Tools # after directory field: "python/pdf-tools" # exact casing/layout from repo HEAD install(...) # resolves and installs
Defensive patterns
Strategy: try-catch
Try / catch
match install(&db, &skill, &app).await {
Err(e) if e.to_string().contains("SKILL_DIR_NOT_FOUND") => {
let v: serde_json::Value = serde_json::from_str(&e.to_string())?;
let missing = v["context"]["path"].as_str().unwrap_or("");
// open the repo URL, locate the real folder, refresh catalog, offer re-install
}
other => other?,
} Prevention
- Refresh the discovery list right before installing so path metadata matches repo HEAD.
- Match path casing exactly, especially when installing from case-sensitive platforms.
When it happens
Trigger: skill.directory = "python/pdf-tools" but the cloned repo has "python/pdf_tools" or moved it to "tools/pdf-tools" on the resolved branch; the default branch changed and the path only exists on another branch; the discovery entry is stale relative to the repo's HEAD.
Common situations: Upstream reorganizes folders after the aggregator indexed them; skills.sh metadata drift; case-sensitivity differences between macOS (where the entry was authored) and Linux (where install runs); wrong branch metadata in DiscoverableSkill.repo_branch.
Related errors
AI-assisted analysis of farion1231/cc-switch@06082e189d (2026-08-20).
Data as JSON: /api/errors/3d65c7e497632e57.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/services/skill.rs:845
.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 06082e189d)