{"record":{"id":"5d5c0f0853e35954","repo":"charmbracelet/crush","slug":"name-q-must-match-directory-q","errorCode":null,"errorMessage":"name %q must match directory %q","messagePattern":"name %q must match directory %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skills/skills.go","lineNumber":131,"sourceCode":"\tlatestStates = cloneStates(states)\n\tlatestStatesMu.Unlock()\n}\n\n// Validate checks if the skill meets spec requirements.\nfunc (s *Skill) Validate() error {\n\tvar errs []error\n\n\tif s.Name == \"\" {\n\t\terrs = append(errs, errors.New(\"name is required\"))\n\t} else {\n\t\tif len(s.Name) > MaxNameLength {\n\t\t\terrs = append(errs, fmt.Errorf(\"name exceeds %d characters\", MaxNameLength))\n\t\t}\n\t\tif !namePattern.MatchString(s.Name) {\n\t\t\terrs = append(errs, errors.New(\"name must be alphanumeric with hyphens, no leading/trailing/consecutive hyphens\"))\n\t\t}\n\t\tif s.Path != \"\" && !strings.EqualFold(filepath.Base(s.Path), s.Name) {\n\t\t\terrs = append(errs, fmt.Errorf(\"name %q must match directory %q\", s.Name, filepath.Base(s.Path)))\n\t\t}\n\t}\n\n\tif s.Description == \"\" {\n\t\terrs = append(errs, errors.New(\"description is required\"))\n\t} else if len(s.Description) > MaxDescriptionLength {\n\t\terrs = append(errs, fmt.Errorf(\"description exceeds %d characters\", MaxDescriptionLength))\n\t}\n\n\tif len(s.Compatibility) > MaxCompatibilityLength {\n\t\terrs = append(errs, fmt.Errorf(\"compatibility exceeds %d characters\", MaxCompatibilityLength))\n\t}\n\n\treturn errors.Join(errs...)\n}\n\n// Parse parses a SKILL.md file from disk.\nfunc Parse(path string) (*Skill, error) {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/skills/skills.go#L113-L149","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","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"],"exampleFix":"// before\n// skills/code-review/SKILL.md\n// name: review-code\n// after\n// skills/code-review/SKILL.md\n// name: code-review","handlingStrategy":"validation","validationCode":"func validateSkillPath(name, path string) error {\n\tif path == \"\" {\n\t\treturn nil\n\t}\n\tbase := filepath.Base(path)\n\tif !strings.EqualFold(base, name) {\n\t\treturn fmt.Errorf(\"skill name %q does not match directory %q\", name, base)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"skills, err := Parse(dir)\nif err != nil {\n\tvar joined interface{ Unwrap() []error }\n\tif errors.As(err, &joined) {\n\t\tfor _, e := range err.(interface{ Unwrap() []error }).Unwrap() {\n\t\t\tlog.Printf(\"skill %s: %v\", dir, e)\n\t\t}\n\t}\n}","preventionTips":["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"],"tags":["skills","validation","frontmatter"],"backgroundTag":"skill-name-directory-mismatch","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}