Hmbown/CodeWhale · error
refusing to remove skill outside Codewhale-owned roots
Error message
refusing to remove skill outside Codewhale-owned roots
What it means
`remove_skill` only deletes skills inside roots marked writable/Codewhale-owned. Skills resolved from bundled, external, or otherwise non-owned roots cannot be removed through this API, protecting content Codewhale does not manage from deletion.
Solutions
- Only remove skills that live under a writable Codewhale-owned skills directory.
- For external skills, remove the owned imported copy; the external original is left in place by design.
- Remount/repair the skills directory so it is writable, and confirm the configured skills dir points at the real owned root.
Example fix
// before
mutation.execute_sync(Mutation::Remove { skill_id: external_skill_id, .. })?; // rejected
// after
mutation.execute_sync(Mutation::Remove { skill_id: owned_imported_id, .. })?; // owned copy only Defensive patterns
Strategy: validation
Validate before calling
let (skill, _) = find_audited_skill(ctx, &skill_id)?;
if !skill.root.is_writable_owned() {
return Err(anyhow!("refusing to remove: skill is outside Codewhale-owned roots"));
} Type guard
fn removable(skill: &AuditedSkill) -> bool {
skill.root.is_writable_owned() && skill.source_kind == SkillSourceKind::CodeWhaleManaged
} Prevention
- Remove only managed skills inside owned roots.
- Keep the skills directory on a writable filesystem.
- Use remove for owned copies only; external originals stay in place.
When it happens
Trigger: Calling the `Remove` mutation (`execute_sync` → `remove_skill`) for a skill whose `root.is_writable_owned()` is false — bundled skills, unimported external skills, or owned dirs on read-only mounts.
Common situations: Trying to delete a bundled example skill; attempting to remove an external skill that was never imported; the configured skills directory is read-only (container image, restored snapshot).
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- only Codewhale managed skills can be removed
- only CodeWhale managed skills can be trusted
- refusing to mutate non-owned root
- refusing to trust skill outside Codewhale-owned roots
- refusing to update skill outside Codewhale-owned roots
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/9a5545928cb5d265.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skills/mutation.rs:942
action: SkillActionKind::Update,
name: skill_id.canonical_name,
scope,
safe_target_path: safe_display_path(&path, Some(ctx.workspace), ctx.home),
before_digest: before,
after_digest: None,
outcome: SkillMutationOutcome::NetworkDenied(host),
}),
}
}
fn remove_skill(
skill_id: AuditedSkillId,
expected_digest: Option<String>,
ctx: &MutationContext<'_>,
) -> Result<SkillMutationReceipt> {
let (skill, path) = find_audited_skill(ctx, &skill_id)?;
if !skill.root.is_writable_owned() {
bail!("refusing to remove skill outside Codewhale-owned roots");
}
if skill.source_kind != SkillSourceKind::CodeWhaleManaged {
bail!("only Codewhale managed skills can be removed");
}
let skills_dir = validate_owned_skill_path(ctx, &skill, &path)?;
let before = verify_expected_digest(&path, expected_digest.as_deref())?;
let scope = match skill.root.kind {
SkillRootKind::CodeWhaleProject => SkillScope::Project,
SkillRootKind::CodeWhaleGlobal => SkillScope::Global,
_ => SkillScope::Logical,
};
let package_name = on_disk_package_name(&skill_id)?;
validate_owned_skill_path(ctx, &skill, &path)?;
install::uninstall(package_name, &skills_dir)?;
Ok(SkillMutationReceipt {
action: SkillActionKind::Remove,
name: skill_id.canonical_name,
scope,View on GitHub (pinned to 73e0f67d83)