{"record":{"id":"739ac01646853496","repo":"Hmbown/CodeWhale","slug":"owned-skill-path-does-not-exist","errorCode":null,"errorMessage":"owned skill path {} does not exist","messagePattern":"owned skill path (.+?) does not exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/mutation.rs","lineNumber":304,"sourceCode":"    let anchor = owned_anchor(ctx.workspace, ctx.home, target)?;\n    validate_owned_target_chain(anchor, &expected, true)?;\n    Ok(expected)\n}\n\n/// Validate a real direct child of an already validated owned skills root.\n/// Returns false only when a missing child is permitted.\nfn validate_owned_child(skills_dir: &Path, child: &Path, require_existing: bool) -> Result<bool> {\n    if child.parent() != Some(skills_dir) {\n        bail!(\n            \"refusing to mutate path {} outside direct owned root {}\",\n            child.display(),\n            skills_dir.display()\n        );\n    }\n    let exists = checked_real_directory(child)?;\n    if !exists {\n        if require_existing {\n            bail!(\"owned skill path {} does not exist\", child.display());\n        }\n        return Ok(false);\n    }\n\n    let canonical_root = fs::canonicalize(skills_dir).with_context(|| {\n        format!(\n            \"failed to resolve owned skill root {}\",\n            skills_dir.display()\n        )\n    })?;\n    let canonical_child = fs::canonicalize(child)\n        .with_context(|| format!(\"failed to resolve owned skill path {}\", child.display()))?;\n    if canonical_child.parent() != Some(canonical_root.as_path()) {\n        bail!(\n            \"owned skill path {} escapes direct root {}\",\n            child.display(),\n            skills_dir.display()\n        );","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/skills/mutation.rs#L286-L322","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-run skill discovery to confirm the skill still exists on disk before updating; skip it if gone.","Check the expected package directory name (on-disk casing) matches what is actually in the skills root.","If the skill is legitimately missing, re-install it instead of updating."],"exampleFix":"// before\nfor skill in stale_audit.skills {\n    update_skill(&ctx, &skill)?; // fails if deleted\n}\n// after\nfor skill in rediscover_skills(&ctx)? {\n    update_skill(&ctx, &skill)?;\n}","handlingStrategy":"validation","validationCode":"fn skill_exists(skills_dir: &std::path::Path, package_name: &str) -> bool {\n    std::path::Path::new(skills_dir).join(package_name).is_dir()\n}","typeGuard":null,"tryCatchPattern":"// skip or reinstall missing skills instead of failing the batch\nmatch update_skill(&ctx, &skill) {\n    Err(e) if e.to_string().contains(\"does not exist\") => {\n        eprintln!(\"skill {} vanished; reinstalling\", skill.id.name);\n        install_skill(&ctx, &skill)?\n    }\n    other => other?,\n}","preventionTips":["Re-discover skills immediately before updating instead of reusing old audit results.","Match the on-disk package directory name exactly (casing included).","Avoid external deletion of skill dirs (git clean / rm) while a mutation session is in flight."],"tags":["skills","file-not-found","stale-state","rust"],"backgroundTag":"file-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}