{"record":{"id":"f56cf0a72e52e869","repo":"larksuite/cli","slug":"errunsatisfiedskilldependency","errorCode":"ErrUnsatisfiedSkillDependency","errorMessage":"%w: skill %q requires skill %q, but %q is absent from the composed skill tree","messagePattern":"%w: skill %q requires skill %q, but %q is absent from the composed skill tree","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillpolicy/dependencies.go","lineNumber":107,"sourceCode":"\treturn out, nil\n}\n\n// validateRequiredSkills checks the already-composed owner manifest. It must\n// run after Base -> Allow -> Remove -> Overlay so no validation branch can\n// accidentally disagree with the tree that list/read actually serves.\nfunc validateRequiredSkills(composed *overlayFS) error {\n\tif composed == nil {\n\t\treturn nil\n\t}\n\tnames := make([]string, 0, len(composed.owner))\n\tfor name := range composed.owner {\n\t\tnames = append(names, name)\n\t}\n\tsort.Strings(names)\n\tfor _, name := range names {\n\t\tfor _, dependency := range composed.owner[name].manifest.requiredSkills {\n\t\t\tif _, present := composed.owner[dependency]; !present {\n\t\t\t\treturn fmt.Errorf(\"%w: skill %q requires skill %q, but %q is absent from the composed skill tree\", ErrUnsatisfiedSkillDependency, name, dependency, dependency)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":89,"sourceCodeEnd":113,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillpolicy/dependencies.go#L89-L113","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\n---\nmetadata:\n  requires:\n    skills: [deploy-runbook]   # not shipped\n---\n// after (ship deploy-runbook/ with SKILL.md, or fix the name)\n---\nmetadata:\n  requires:\n    skills: [deployment]        # existing skill\n---","handlingStrategy":"validation","validationCode":"// pre-compute the closure before ResolveWithReferences\nmanifests := map[string][]string{} // skill -> requiredSkills from SKILL.md\nvar missing []string\nvar visit func(string)\nvisit = func(name string) {\n    for _, dep := range manifests[name] {\n        if _, ok := manifests[dep]; !ok { missing = append(missing, name+\" -> \"+dep); continue }\n        visit(dep)\n    }\n}\nvisit(rootSkill)\nif len(missing) > 0 { return fmt.Errorf(\"unresolved skill dependencies: %v\", missing) }","typeGuard":null,"tryCatchPattern":"if err := resolver.ResolveWithReferences(...); err != nil {\n    if errors.Is(err, ErrUnsatisfiedSkillDependency) {\n        return fmt.Errorf(\"incomplete skill distribution: %w (ship the missing skill or drop the requires entry)\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["skillpolicy","dependency","composition","unresolved-reference"],"backgroundTag":"unsatisfied-skill-dependency","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}