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

  1. Unwrap with errors.Is/errors.As to find the specific cause (ErrNoBaseSkillContent, ErrUnsatisfiedSkillDependency, skillref.ErrInvalidRemap, or a scan error naming the bad skill).
  2. Fix the plugin's SkillsOverlay: keep top-level entries as valid <skill>/ dirs with valid SKILL.md.
  3. Align Allow/Remove with the actual base tree skill names, and never remove a skill that a retained skill requires.
  4. 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

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


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/b8fd9a2246b34f32. Report an issue: GitHub.