charmbracelet/crush · error
name %q must match directory %q
Error message
name %q must match directory %q
What it means
Skill.Validate() enforces that a Skill's Name field matches the base name of its directory path (case-insensitive). This error is thrown when s.Path is non-empty and filepath.Base(s.Path) does not equalFold s.Name, keeping the on-disk skill directory name consistent with its declared name.
Source
Thrown at internal/skills/skills.go:131
latestStates = cloneStates(states)
latestStatesMu.Unlock()
}
// Validate checks if the skill meets spec requirements.
func (s *Skill) Validate() error {
var errs []error
if s.Name == "" {
errs = append(errs, errors.New("name is required"))
} else {
if len(s.Name) > MaxNameLength {
errs = append(errs, fmt.Errorf("name exceeds %d characters", MaxNameLength))
}
if !namePattern.MatchString(s.Name) {
errs = append(errs, errors.New("name must be alphanumeric with hyphens, no leading/trailing/consecutive hyphens"))
}
if s.Path != "" && !strings.EqualFold(filepath.Base(s.Path), s.Name) {
errs = append(errs, fmt.Errorf("name %q must match directory %q", s.Name, filepath.Base(s.Path)))
}
}
if s.Description == "" {
errs = append(errs, errors.New("description is required"))
} else if len(s.Description) > MaxDescriptionLength {
errs = append(errs, fmt.Errorf("description exceeds %d characters", MaxDescriptionLength))
}
if len(s.Compatibility) > MaxCompatibilityLength {
errs = append(errs, fmt.Errorf("compatibility exceeds %d characters", MaxCompatibilityLength))
}
return errors.Join(errs...)
}
// Parse parses a SKILL.md file from disk.
func Parse(path string) (*Skill, error) {View on GitHub (pinned to 7944b8e522)
Solutions
- Rename the skill directory to exactly match the `name:` field in SKILL.md frontmatter (case-insensitive)
- Or update the `name:` field in SKILL.md frontmatter to match the directory's base name
- Check for stray whitespace, slashes, or case mismatches in the Path value passed to the Skill
Example fix
// before // skills/code-review/SKILL.md // name: review-code // after // skills/code-review/SKILL.md // name: code-review
Defensive patterns
Strategy: validation
Validate before calling
func validateSkillPath(name, path string) error {
if path == "" {
return nil
}
base := filepath.Base(path)
if !strings.EqualFold(base, name) {
return fmt.Errorf("skill name %q does not match directory %q", name, base)
}
return nil
} Try / catch
skills, err := Parse(dir)
if err != nil {
var joined interface{ Unwrap() []error }
if errors.As(err, &joined) {
for _, e := range err.(interface{ Unwrap() []error }).Unwrap() {
log.Printf("skill %s: %v", dir, e)
}
}
} Prevention
- Generate skill directories from the frontmatter name (or vice versa) with a script so they never drift
- Run skill.Validate() in CI over all skill directories
- Avoid renaming one side (folder or name field) without the other; grep for the old name after renames
- Use lowercase-hyphen directory names identical to the name field to sidestep case issues
When it happens
Trigger: Calling Validate() (directly or via Parse/ParseContent flows that validate) on a Skill whose Name does not case-insensitively match filepath.Base(s.Path); e.g. Name "my-skill" with Path "/skills/MySkill/" or a directory like "/skills/code-review".
Common situations: Renaming the `name:` field in SKILL.md frontmatter without renaming the directory; renaming/moving the skill folder without updating frontmatter; cloning a skill into a differently named directory; typos or trailing whitespace in either the name or the path.
Related errors
- name is required
- description is required
- name exceeds %d characters
- description exceeds %d characters
- compatibility exceeds %d characters
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/5d5c0f0853e35954.
Report an issue: GitHub.