larksuite/cli · error
%s: %q is not a valid skill name
Error message
%s: %q is not a valid skill name
What it means
A top-level directory name fails skillref.ValidSkillName (isSkillName): empty, dotted, or otherwise invalid as a skill identifier. Skill directory names are part of the reference contract, so malformed names are rejected at composition time.
Source
Thrown at internal/skillpolicy/resolver.go:181
// scanSkillTree validates and snapshots a skill tree's top level in one
// pass. The returned set is the only source used by validation and overlay
// composition, so a mutable FS cannot swap unvalidated names between phases.
func scanSkillTree(label string, source fs.FS) (skillTreeSnapshot, error) {
snapshot := skillTreeSnapshot{source: source, skills: map[string]skillManifest{}}
if source == nil {
return snapshot, nil
}
entries, err := fs.ReadDir(source, ".")
if err != nil {
return snapshot, fmt.Errorf("%s: cannot read root: %w", label, err)
}
for _, e := range entries {
name := e.Name()
if !e.IsDir() {
return snapshot, fmt.Errorf("%s: %q is not a directory; every %s entry must be a <skill>/ dir", label, name, label)
}
if !isSkillName(name) {
return snapshot, fmt.Errorf("%s: %q is not a valid skill name", label, name)
}
ok, err := skillExists(source, name)
if err != nil {
return snapshot, fmt.Errorf("%s: probing skill %q: %w", label, name, err)
}
if !ok {
return snapshot, fmt.Errorf("%s: skill %q is missing SKILL.md", label, name)
}
manifest, err := readSkillManifest(source, name)
if err != nil {
return snapshot, fmt.Errorf("%s: skill %q has invalid metadata: %w", label, name, err)
}
snapshot.skills[name] = manifest
}
return snapshot, nil
}
// validateSelection rejects allow/remove entries that cannot compose againstView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Rename the offending directory (named in the message) to a valid skill name per skillref.ValidSkillName
- Exclude non-skill hidden/system directories from the embedded tree
- Pre-validate candidate names with skillref.ValidSkillName before adding a skill
- Check for accidental dot-directories swept into an embed pattern
Example fix
// before overlay/.github/ // invalid entry // after overlay/deploy-guide/ // valid skill name; move .github out of the tree
Defensive patterns
Strategy: validation
Validate before calling
for _, name := range dirNames {
if !skillref.ValidSkillName(name) { return fmt.Errorf("invalid skill name %q", name) }
} Try / catch
_, err := skillpolicy.ResolveWithReferences(base, specs)
if err != nil && strings.Contains(err.Error(), "is not a valid skill name") { /* rename dir */ } Prevention
- Validate directory names with skillref.ValidSkillName before adding skills
- Exclude hidden/system dirs from embeds
- Use lowercase-kebab skill names consistently
When it happens
Trigger: ResolveWithReferences over a Base/Overlay FS containing a directory whose name is not a valid skill name (e.g. leading dots, slashes cannot occur at top level, empty or reserved characters).
Common situations: Directories like '.github', '__pycache__', 'my skill' with spaces, or a renamed skill directory using PascalCase when the contract expects a specific naming convention.
Related errors
- %s: %q is not a directory; every %s entry must be a <skill>/
- Input.Fields[%d].Name %q is not a canonical flag name
- Invalid column: {column!r}
- Invalid column index: {index}
- anchor outside sheet: {position!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/33a958e342d6098e.
Report an issue: GitHub.