larksuite/cli · error
plugin %q skill spec: %w
Error message
plugin %q skill spec: %w
What it means
A generic attribution wrapper: a plugin's skill spec (Base, Overlay, Allow/Remove selection, required-skill closure, or ReferenceRemaps) failed validation or scanning, and the resolver wraps the cause as 'plugin "<owner>" skill spec: <cause>'. It applies whenever the failure is attributable to the plugin's contribution rather than the host base (which uses ErrInvalidHostBase).
Source
Thrown at internal/skillpolicy/resolver.go:102
return Resolution{}, err
}
return Resolution{Content: base, References: refs}, nil
}
owner, spec := specs[0].PluginName, specs[0].SkillsOverlay
lower := base
lowerLabel := "host Base"
if spec.Base != nil {
lower = protectPluginFS(owner, "Base", spec.Base)
lowerLabel = "plugin Base"
}
upper := protectPluginFS(owner, "Overlay", spec.Overlay)
lowerSnapshot, err := scanSkillTree(lowerLabel, lower)
if err != nil {
if spec.Base == nil {
return Resolution{}, fmt.Errorf("%w: %w", ErrInvalidHostBase, err)
}
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
upperSnapshot, err := scanSkillTree("plugin Overlay", upper)
if err != nil {
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
if err := validateSelection(lowerSnapshot, spec); err != nil {
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
var content fs.FS
if lower == nil && upper == nil {
content = nil
} else {
composed := newOverlayFS(lowerSnapshot, upperSnapshot, spec.Remove, spec.Allow)
if err := validateRequiredSkills(composed); err != nil {
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
content = composed
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Unwrap with errors.Is/errors.As to find the specific cause (ErrNoBaseSkillContent, ErrUnsatisfiedSkillDependency, skillref.ErrInvalidRemap, or a scan error naming the bad skill).
- Fix the plugin's SkillsOverlay: keep top-level entries as valid <skill>/ dirs with valid SKILL.md.
- Align Allow/Remove with the actual base tree skill names, and never remove a skill that a retained skill requires.
- Validate ReferenceRemaps against the composed tree — both From and To must be parseable and the target must exist.
Example fix
// before (overlay has a stray top-level file) overlay/README.md overlay/my-skill/SKILL.md // after — every top-level entry must be a skill directory overlay/my-skill/SKILL.md overlay/other-skill/SKILL.md
Defensive patterns
Strategy: validation
Validate before calling
// pre-validate a plugin SkillsOverlay before registration
for _, e := range must(fs.ReadDir(overlay, ".")) { // every top entry must be a skill dir
if !e.IsDir() { return fmt.Errorf("overlay: %q is not a skill dir", e.Name()) }
if _, err := fs.Stat(overlay, e.Name()+"/SKILL.md"); err != nil {
return fmt.Errorf("overlay skill %q missing SKILL.md", e.Name())
}
}
for _, name := range spec.Allow { /* must exist in base */ }
for _, name := range spec.Remove { /* must exist in base and not be required */ } Try / catch
if err != nil {
var ownedErr error
if errors.As(err, new(*fs.PathError)) || strings.Contains(err.Error(), "skill spec:") {
return fmt.Errorf("plugin skill spec invalid — check Overlay/Allow/Remove/ReferenceRemaps: %w", err)
}
return err
} Prevention
- Keep the Overlay top level exclusively valid <skill>/ directories with SKILL.md.
- Cross-check Allow/Remove names against the actual base tree before shipping.
- Never remove a skill required by another retained skill.
- Validate ReferenceRemaps targets exist in the composed tree; test resolution in the plugin's CI.
When it happens
Trigger: ResolveWithReferences with a spec whose Base is non-nil and scanSkillTree fails on plugin Base; scanSkillTree fails on plugin Overlay; validateSelection rejects Allow/Remove names (invalid name, not in base, or no base content); validateRequiredSkills finds an unsatisfied dependency; resolveReferences hits a bad remap.
Common situations: A plugin ships an Overlay directory containing a stray file at top level; Allow references a skill name absent from the base; Remove names a skill the base never had; a retained skill requires another skill the plugin removed; a ReferenceRemap points at a nonexistent target.
Related errors
- Invalid column: {column!r}
- Invalid column index: {index}
- anchor outside sheet: {position!r}
- Missing row_count/column_count for sheet {sheet_title(sheet)
- Missing sheet_id for sheet {title!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/b8fd9a2246b34f32.
Report an issue: GitHub.