Hmbown/CodeWhale · error

import source must be a compatible external skill

Error message

import source must be a compatible external skill

What it means

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.

Solutions

  1. Verify the source ID refers to an external (not managed/imported) skill by inspecting the audit listing before calling import.
  2. Re-scan/re-audit the skills directories so the external package is classified as `CompatibleExternal`; fix its SKILL.md metadata if classification failed.
  3. If the skill is already managed it does not need importing — update it instead, or remove it first for a fresh import.
  4. Check that the configured external/compatible skills directory actually contains the package you intended to import.

Example fix

// before
mutator.import_external(&managed_skill_id, target, policy, &ctx)?; // rejects
// after
let audited = audit.find(&external_skill_id)?;
assert_eq!(audited.source_kind, SkillSourceKind::CompatibleExternal);
mutator.import_external(&external_skill_id, target, policy, &ctx)?;
Defensive patterns

Strategy: validation

Validate before calling

let (skill, _) = find_audited_skill(ctx, &source_id)?;
if skill.source_kind != SkillSourceKind::CompatibleExternal {
    return Err(anyhow!("source {:?} is not a compatible external skill", source_id));
}

Type guard

fn is_importable(skill: &AuditedSkill) -> bool {
    matches!(skill.source_kind, SkillSourceKind::CompatibleExternal) && !skill.path_unsafe
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

            scope: target.as_skill_scope(),
            safe_target_path: safe_display_path(&skills_dir, Some(ctx.workspace), ctx.home),
            before_digest: None,
            after_digest: None,
            outcome: SkillMutationOutcome::NetworkDenied(host),
        }),
    }
}

fn import_external(
    source_id: AuditedSkillId,
    expected_digest: String,
    target: SkillTargetScope,
    conflict_policy: ConflictPolicy,
    ctx: &MutationContext<'_>,
) -> Result<SkillMutationReceipt> {
    let (source_skill, source_path) = find_audited_skill(ctx, &source_id)?;
    if source_skill.source_kind != SkillSourceKind::CompatibleExternal {
        bail!("import source must be a compatible external skill");
    }
    if source_skill.path_unsafe {
        bail!("refusing to import unsafe external skill package");
    }

    let owned_snap = scan_with_configured(
        ctx.workspace,
        ctx.home,
        ctx.configured_skills_dir,
        SkillAuditMode::OwnedOnly,
        None,
    );
    let owned_has_name = owned_snap
        .skills
        .iter()
        .any(|s| s.id.canonical_name == source_id.canonical_name);

    if !owned_has_name && !source_skill.import_candidate {

View on GitHub (pinned to 73e0f67d83)