Hmbown/CodeWhale · error
skill is not an import candidate
Error message
skill is not an import candidate
What it means
Thrown when `import_external` would silently import a skill the caller never opted into: the target owned scope does not already contain the canonical name, and the audit did not mark the skill as `import_candidate`. Import is either explicit-candidate-only or a deduplicating AlreadyPresent no-op.
Solutions
- Import the skill through the flow that marks it as an import candidate (accept it from the audit/suggestion listing) instead of calling import directly.
- Re-run the audit so `import_candidate` is refreshed, then retry.
- Use the correct `SkillTargetScope` where the skill's canonical name already exists if the intent was to refresh an existing import.
Defensive patterns
Strategy: validation
Validate before calling
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 {
return Err(anyhow!("skill is not an import candidate"));
} Prevention
- Import only skills surfaced as candidates by the audit.
- Refresh the audit before importing so import_candidate is current.
- Pass the SkillTargetScope that actually holds the skill's canonical name when refreshing.
When it happens
Trigger: Calling `import_external` where the owned snapshot has no skill matching `source_id.canonical_name` and `source_skill.import_candidate` is false — i.e. the external skill was never flagged as an import suggestion by the audit.
Common situations: Pointing import at an arbitrary external skill that was never surfaced as a candidate; a stale audit predating the candidate flag; passing a `SkillTargetScope` different from the one that holds the name (so `owned_has_name` is false).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- import source must be a compatible external skill
- bundle contains conflicting or rejected entries
- Choose one recording to import.
- Codewhale runtime event file is empty.
- destination already exists with different content
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/4e6c1d9bb5fb35ef.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skills/mutation.rs:670
}
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 {
bail!("skill is not an import candidate");
}
let before = verify_expected_digest(&source_path, Some(&expected_digest))?;
let skills_dir = prepare_owned_target(ctx.workspace, ctx.home, target)?;
let anchor = owned_anchor(ctx.workspace, ctx.home, target)?;
let want_kind = match target {
SkillTargetScope::Project => SkillRootKind::CodeWhaleProject,
SkillTargetScope::Global => SkillRootKind::CodeWhaleGlobal,
};
let existing_in_target: Vec<&AuditedSkill> = owned_snap
.skills
.iter()
.filter(|s| s.id.canonical_name == source_id.canonical_name)
.filter(|s| s.root.kind == want_kind)
.collect();
View on GitHub (pinned to 73e0f67d83)