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

  1. Open the repo on GitHub at the reported path (context.path) and find where SKILL.md actually lives now
  2. Refresh the skills.sh listing and reinstall so the corrected directory is picked up
  3. 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

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


AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16). Data as JSON: /api/errors/3d65c7e497632e57. Report an issue: GitHub.