larksuite/cli · error
ErrUnsatisfiedSkillDependency
ErrUnsatisfiedSkillDependency
Error message
%w: skill %q requires skill %q, but %q is absent from the composed skill tree
What it means
validateRequiredSkills walks the composed skill tree and, for each skill's declared requiredSkills, throws a typed ErrUnsatisfiedSkillDependency when a required skill is not present in the composed tree. This is the dependency-closure check: the composition is incomplete, so the skill set cannot be resolved with references safely.
Source
Thrown at internal/skillpolicy/dependencies.go:107
return out, nil
}
// validateRequiredSkills checks the already-composed owner manifest. It must
// run after Base -> Allow -> Remove -> Overlay so no validation branch can
// accidentally disagree with the tree that list/read actually serves.
func validateRequiredSkills(composed *overlayFS) error {
if composed == nil {
return nil
}
names := make([]string, 0, len(composed.owner))
for name := range composed.owner {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
for _, dependency := range composed.owner[name].manifest.requiredSkills {
if _, present := composed.owner[dependency]; !present {
return fmt.Errorf("%w: skill %q requires skill %q, but %q is absent from the composed skill tree", ErrUnsatisfiedSkillDependency, name, dependency, dependency)
}
}
}
return nil
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Add the missing dependency skill to the composed skill tree / distribution
- Fix the dependency name in the requiring skill's SKILL.md to match an existing skill
- Include all transitive dependencies in the composition inputs passed to ResolveWithReferences
- If the dependency no longer exists, remove or replace the stale entry in requires.skills
Example fix
// before
---
metadata:
requires:
skills: [deploy-runbook] # not shipped
---
// after (ship deploy-runbook/ with SKILL.md, or fix the name)
---
metadata:
requires:
skills: [deployment] # existing skill
--- Defensive patterns
Strategy: validation
Validate before calling
// pre-compute the closure before ResolveWithReferences
manifests := map[string][]string{} // skill -> requiredSkills from SKILL.md
var missing []string
var visit func(string)
visit = func(name string) {
for _, dep := range manifests[name] {
if _, ok := manifests[dep]; !ok { missing = append(missing, name+" -> "+dep); continue }
visit(dep)
}
}
visit(rootSkill)
if len(missing) > 0 { return fmt.Errorf("unresolved skill dependencies: %v", missing) } Try / catch
if err := resolver.ResolveWithReferences(...); err != nil {
if errors.Is(err, ErrUnsatisfiedSkillDependency) {
return fmt.Errorf("incomplete skill distribution: %w (ship the missing skill or drop the requires entry)", err)
}
return err
} Prevention
- Keep requires.skills in sync with actually shipped skills
- Ship complete distributions including transitive dependencies
- Test plugin distributions by resolving them before release
- Remove stale dependency entries when skills are renamed or deleted
When it happens
Trigger: ResolveWithReferences composed a skill tree where skill X's frontmatter lists a dependency Y, but no directory/skill named Y exists in the composed source (Y missing, misspelled, or not included in the composition inputs).
Common situations: A skill declares a dependency on a skill that was never shipped or was renamed; the composition call includes only a subset of skills, omitting a transitive dependency; a typo in the requires list; a plugin distribution trimmed "unused" skills that others depend on.
Related errors
- cannot read SKILL.md: %w
- SKILL.md frontmatter is not closed
- cannot parse SKILL.md frontmatter: %w
- required skill %q declared by %q is not a valid skill name
- panic: %v
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/f56cf0a72e52e869.
Report an issue: GitHub.