{"record":{"id":"d3d42cd0c348e3c4","repo":"Hmbown/CodeWhale","slug":"import-source-must-be-a-compatible-external-skill","errorCode":null,"errorMessage":"import source must be a compatible external skill","messagePattern":"import source must be a compatible external skill","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/mutation.rs","lineNumber":651,"sourceCode":"            scope: target.as_skill_scope(),\n            safe_target_path: safe_display_path(&skills_dir, Some(ctx.workspace), ctx.home),\n            before_digest: None,\n            after_digest: None,\n            outcome: SkillMutationOutcome::NetworkDenied(host),\n        }),\n    }\n}\n\nfn import_external(\n    source_id: AuditedSkillId,\n    expected_digest: String,\n    target: SkillTargetScope,\n    conflict_policy: ConflictPolicy,\n    ctx: &MutationContext<'_>,\n) -> Result<SkillMutationReceipt> {\n    let (source_skill, source_path) = find_audited_skill(ctx, &source_id)?;\n    if source_skill.source_kind != SkillSourceKind::CompatibleExternal {\n        bail!(\"import source must be a compatible external skill\");\n    }\n    if source_skill.path_unsafe {\n        bail!(\"refusing to import unsafe external skill package\");\n    }\n\n    let owned_snap = scan_with_configured(\n        ctx.workspace,\n        ctx.home,\n        ctx.configured_skills_dir,\n        SkillAuditMode::OwnedOnly,\n        None,\n    );\n    let owned_has_name = owned_snap\n        .skills\n        .iter()\n        .any(|s| s.id.canonical_name == source_id.canonical_name);\n\n    if !owned_has_name && !source_skill.import_candidate {","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/skills/mutation.rs#L633-L669","documentation":"This error is thrown by `import_external` in the skills mutation API when the skill selected as the import source is not of `SkillSourceKind::CompatibleExternal`. Only skills audited as compatible external packages may be copied into Codewhale-owned directories; managed, bundled, or already-imported sources are rejected to keep provenance and trust markers correct.","triggerScenarios":"Calling `import_external` (via mutation `execute_sync`) with a `source_id` that resolves through `find_audited_skill` to a skill whose `source_kind != SkillSourceKind::CompatibleExternal` — e.g. importing a Codewhale-managed skill, an already-imported skill, or an external package that failed compatibility classification.","commonSituations":"Passing the ID of a project-owned or managed skill instead of an external one; double-importing a skill that is already in the owned directory (it is now managed, not external); the external package's SKILL.md metadata failed the compatible-external audit so it was classified differently.","solutions":["Verify the source ID refers to an external (not managed/imported) skill by inspecting the audit listing before calling import.","Re-scan/re-audit the skills directories so the external package is classified as `CompatibleExternal`; fix its SKILL.md metadata if classification failed.","If the skill is already managed it does not need importing — update it instead, or remove it first for a fresh import.","Check that the configured external/compatible skills directory actually contains the package you intended to import."],"exampleFix":"// before\nmutator.import_external(&managed_skill_id, target, policy, &ctx)?; // rejects\n// after\nlet audited = audit.find(&external_skill_id)?;\nassert_eq!(audited.source_kind, SkillSourceKind::CompatibleExternal);\nmutator.import_external(&external_skill_id, target, policy, &ctx)?;","handlingStrategy":"validation","validationCode":"let (skill, _) = find_audited_skill(ctx, &source_id)?;\nif skill.source_kind != SkillSourceKind::CompatibleExternal {\n    return Err(anyhow!(\"source {:?} is not a compatible external skill\", source_id));\n}","typeGuard":"fn is_importable(skill: &AuditedSkill) -> bool {\n    matches!(skill.source_kind, SkillSourceKind::CompatibleExternal) && !skill.path_unsafe\n}","tryCatchPattern":null,"preventionTips":["Check the audit listing's source_kind before importing.","Never pass managed or imported skill IDs to import_external.","Refresh the skill audit after changing external skill packages."],"tags":["skills","import","validation"],"backgroundTag":"incompatible-source-type","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"}