{"record":{"id":"e0b4e06708a4a041","repo":"charmbracelet/crush","slug":"w-s-e0b4e0","errorCode":null,"errorMessage":"%w: %s","messagePattern":"%w: %s","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skills/catalog.go","lineNumber":71,"sourceCode":"\t\t\tName:          skill.Name,\n\t\t\tDescription:   skill.Description,\n\t\t\tLabel:         label,\n\t\t\tSource:        source,\n\t\t\tUserInvocable: skill.UserInvocable,\n\t\t})\n\t}\n\treturn entries\n}\n\n// FindEffective returns the named skill from the given active skill\n// set.\nfunc FindEffective(active []*Skill, skillID string) (*Skill, error) {\n\tfor _, skill := range active {\n\t\tif skill.SkillFilePath == skillID {\n\t\t\treturn skill, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"%w: %s\", ErrSkillNotFound, skillID)\n}\n\n// ReadContent reads the contents of a visible skill by ID and returns\n// the raw bytes along with metadata about the skill.\nfunc ReadContent(active []*Skill, skillPaths []string, workingDir string, skillID string) ([]byte, SkillReadResult, error) {\n\tskill, err := FindEffective(active, skillID)\n\tif err != nil {\n\t\treturn nil, SkillReadResult{}, err\n\t}\n\n\t_, source := skillLabel(skillPaths, workingDir, skill)\n\tresult := SkillReadResult{\n\t\tName:        skill.Name,\n\t\tDescription: skill.Description,\n\t\tSource:      source,\n\t\tBuiltin:     skill.Builtin,\n\t}\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/skills/catalog.go#L53-L89","documentation":"FindEffective looks up a skill by its exact SkillFilePath among the active skills and returns ErrSkillNotFound wrapped with the requested ID when no match exists. This is a sentinel-wrapped error (errors.Is friendly), signaling the caller asked for a skill ID that is not currently loaded/discovered. ReadContent propagates it when resolving a skill by ID.","triggerScenarios":"Calling skills.ReadContent (or FindEffective directly) with a skillID string that does not exactly equal any active skill's SkillFilePath — including when the skill exists but was not discovered (bad directory), was filtered out, or the caller passed a name instead of a file path.","commonSituations":"Typos in the skill ID passed by the model or user; skill directory renamed/moved so SkillFilePath changed; skill failed validation during discovery and is not in the active list; case mismatch in the path.","solutions":["List the active skills and confirm the exact SkillFilePath string to pass (IDs are full file paths, not skill names)","Run skill discovery again or fix the skill directory so the SKILL.md is discovered and validated","Check the discovery state (skills.GetLatestStates) — the skill may be present but in StateError due to a validation failure","Match the ID exactly, including case and path separators"],"exampleFix":"// before\ncontent, err := skills.ReadContent(active, paths, dir, \"my-skill\")\n\n// after — use the discovered skill's file path\nfor _, s := range active {\n    if s.Name == \"my-skill\" {\n        content, err = skills.ReadContent(active, paths, dir, s.SkillFilePath)\n    }\n}","handlingStrategy":"type-guard","validationCode":"func skillExists(active []*skills.Skill, id string) bool {\n    return slices.ContainsFunc(active, func(s *skills.Skill) bool { return s.SkillFilePath == id })\n}","typeGuard":"func findSkill(active []*skills.Skill, id string) (*skills.Skill, bool) {\n    for _, s := range active {\n        if s.SkillFilePath == id { return s, true }\n    }\n    return nil, false\n}","tryCatchPattern":"content, result, err := skills.ReadContent(active, paths, dir, skillID)\nif err != nil {\n    if errors.Is(err, skills.ErrSkillNotFound) {\n        return fmt.Errorf(\"unknown skill %q; pick one of the active skill paths\", skillID)\n    }\n    return err\n}","preventionTips":["Always pass SkillFilePath, never the skill's display name","Refresh the active skill list before lookups after config or directory changes","Inspect skills.GetLatestStates to confirm the skill discovered successfully","Handle ErrSkillNotFound explicitly since it is a sentinel error"],"tags":["skills","not-found","lookup"],"backgroundTag":"skill-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}