Hmbown/CodeWhale · error

skill '{name}' is not installed at {}

Error message

skill '{name}' is not installed at {}

What it means

uninstall() bails with this error when the skill's target directory under skills_dir does not exist; the check runs before any marker or removal logic. The resolved path is printed in the message, so name mismatches and wrong-directory cases are visible.

Source

Thrown at crates/tui/src/skills/install.rs:502

            }
        }
        InstallOutcome::NeedsApproval(_) | InstallOutcome::NetworkDenied(_) => {}
    }
    match outcome {
        InstallOutcome::Installed(installed) => Ok(UpdateResult::Updated(installed)),
        InstallOutcome::NeedsApproval(host) => Ok(UpdateResult::NeedsApproval(host)),
        InstallOutcome::NetworkDenied(host) => Ok(UpdateResult::NetworkDenied(host)),
    }
}

/// Remove a community-installed skill.
///
/// Refuses to touch any directory that doesn't carry the `.installed-from`
/// marker — that's our cue that it's user-owned and not a system skill.
pub fn uninstall(name: &str, skills_dir: &Path) -> Result<()> {
    let target = skill_target_path(name, skills_dir)?;
    if !target.exists() {
        bail!("skill '{name}' is not installed at {}", target.display());
    }
    ensure_target_within_skills_dir(&target, skills_dir)?;
    if !target.join(INSTALLED_FROM_MARKER).exists() {
        return Err(InstallError::NotInstalledHere(name.to_string()).into());
    }
    fs::remove_dir_all(&target)
        .with_context(|| format!("failed to remove {}", target.display()))?;
    Ok(())
}

/// Mark a community-installed skill as trusted, binding the marker to the
/// current package content digest (schema v2).
///
/// Refuses to mark system skills (no `.installed-from`) so the bundled
/// `skill-creator` doesn't accidentally inherit elevated tool privileges.
#[cfg(test)]
pub fn trust(name: &str, skills_dir: &Path) -> Result<()> {
    let target = skill_target_path(name, skills_dir)?;

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. List installed skills and copy the exact, case-sensitive directory name.
  2. Compare the path in the error message against where the skill actually lives; the checked skills_dir is printed.
  3. If the directory exists but lacks the .installed-from marker, the sibling NotInstalledHere error applies: system/user-owned skills are not uninstallable this way.

Example fix

# before
/skill uninstall MySkill
# -> not installed at .../skills/MySkill

# after (actual directory is my-skill)
/skill uninstall my-skill
Defensive patterns

Strategy: validation

Validate before calling

let target = skills_dir.join(name);
if !target.exists() {
    eprintln!("skill '{name}' not present under {}; nothing to uninstall", skills_dir.display());
    return;
}

Prevention

When it happens

Trigger: '/skill uninstall <name>' where the name was never installed, is spelled differently (skill directories are cased names), or the skill lives under a different skills_dir than the one in effect.

Common situations: Typos or case mismatches in the skill name, multiple skills directories (project vs user) with the skill in the other one, and stale memory after a skill was already removed.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/dc7f3bc2d2b8017c. Report an issue: GitHub.