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 against

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Rename the offending directory (named in the message) to a valid skill name per skillref.ValidSkillName
  2. Exclude non-skill hidden/system directories from the embedded tree
  3. Pre-validate candidate names with skillref.ValidSkillName before adding a skill
  4. 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

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


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