Hmbown/CodeWhale · error

owned skill path does not exist

Error message

owned skill path {} does not exist

What it means

When the mutation requires the skill directory to already exist (require_existing), validate_owned_child checks it with checked_real_directory and fails if the path does not exist. Operations like update_skill need an on-disk skill package to modify; a missing directory means the skill was deleted or the name is wrong.

Solutions

  1. Re-run skill discovery to confirm the skill still exists on disk before updating; skip it if gone.
  2. Check the expected package directory name (on-disk casing) matches what is actually in the skills root.
  3. If the skill is legitimately missing, re-install it instead of updating.

Example fix

// before
for skill in stale_audit.skills {
    update_skill(&ctx, &skill)?; // fails if deleted
}
// after
for skill in rediscover_skills(&ctx)? {
    update_skill(&ctx, &skill)?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn skill_exists(skills_dir: &std::path::Path, package_name: &str) -> bool {
    std::path::Path::new(skills_dir).join(package_name).is_dir()
}

Try / catch

// skip or reinstall missing skills instead of failing the batch
match update_skill(&ctx, &skill) {
    Err(e) if e.to_string().contains("does not exist") => {
        eprintln!("skill {} vanished; reinstalling", skill.id.name);
        install_skill(&ctx, &skill)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling validate_owned_skill_path, update_skill (or install/import with require_existing=true) with a child path whose directory does not exist on disk — typically skills_dir.join(on_disk_package_name(skill.id)) after the package was removed, renamed, or the on-disk name differs from the audit record.

Common situations: The skill directory was deleted externally (git clean, manual rm) after auditing; the package folder name casing differs from the expected on-disk name; the audit is stale relative to disk state.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/739ac01646853496. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/skills/mutation.rs:304

    let anchor = owned_anchor(ctx.workspace, ctx.home, target)?;
    validate_owned_target_chain(anchor, &expected, true)?;
    Ok(expected)
}

/// Validate a real direct child of an already validated owned skills root.
/// Returns false only when a missing child is permitted.
fn validate_owned_child(skills_dir: &Path, child: &Path, require_existing: bool) -> Result<bool> {
    if child.parent() != Some(skills_dir) {
        bail!(
            "refusing to mutate path {} outside direct owned root {}",
            child.display(),
            skills_dir.display()
        );
    }
    let exists = checked_real_directory(child)?;
    if !exists {
        if require_existing {
            bail!("owned skill path {} does not exist", child.display());
        }
        return Ok(false);
    }

    let canonical_root = fs::canonicalize(skills_dir).with_context(|| {
        format!(
            "failed to resolve owned skill root {}",
            skills_dir.display()
        )
    })?;
    let canonical_child = fs::canonicalize(child)
        .with_context(|| format!("failed to resolve owned skill path {}", child.display()))?;
    if canonical_child.parent() != Some(canonical_root.as_path()) {
        bail!(
            "owned skill path {} escapes direct root {}",
            child.display(),
            skills_dir.display()
        );

View on GitHub (pinned to 73e0f67d83)