{"record":{"id":"2d2ad4a8498fba80","repo":"charmbracelet/crush","slug":"parsing-frontmatter-w","errorCode":null,"errorMessage":"parsing frontmatter: %w","messagePattern":"parsing frontmatter: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skills/skills.go","lineNumber":175,"sourceCode":"\t\treturn nil, err\n\t}\n\n\tskill.Path = filepath.Dir(path)\n\tskill.SkillFilePath = path\n\n\treturn skill, nil\n}\n\n// ParseContent parses a SKILL.md from raw bytes.\nfunc ParseContent(content []byte) (*Skill, error) {\n\tfrontmatter, body, err := splitFrontmatter(string(content))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar skill Skill\n\tif err := yaml.Unmarshal([]byte(frontmatter), &skill); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing frontmatter: %w\", err)\n\t}\n\n\tskill.Instructions = strings.TrimSpace(body)\n\n\treturn &skill, nil\n}\n\n// splitFrontmatter extracts YAML frontmatter and body from markdown content.\nfunc splitFrontmatter(content string) (frontmatter, body string, err error) {\n\t// Strip UTF-8 BOM for compatibility with editors that include it.\n\tcontent = strings.TrimPrefix(content, \"\\uFEFF\")\n\t// Normalize line endings to \\n for consistent parsing.\n\tcontent = strings.ReplaceAll(content, \"\\r\\n\", \"\\n\")\n\tcontent = strings.ReplaceAll(content, \"\\r\", \"\\n\")\n\n\tlines := strings.Split(content, \"\\n\")\n\tstart := slices.IndexFunc(lines, func(line string) bool {\n\t\treturn strings.TrimSpace(line) != \"\"","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/skills/skills.go#L157-L193","documentation":"ParseContent splits a SKILL.md document into YAML frontmatter and a body, then unmarshals the frontmatter into a Skill struct. This error wraps any yaml.Unmarshal failure, meaning the frontmatter block is not valid YAML or does not match the Skill schema.","triggerScenarios":"Calling ParseContent (or Parse) on SKILL.md content whose frontmatter contains malformed YAML: bad indentation, tabs instead of spaces, unquoted special characters (e.g. colons in unquoted values), wrong types for fields, or missing/unclosed `---` delimiters (which can yield empty/invalid frontmatter).","commonSituations":"Hand-edited SKILL.md with YAML syntax mistakes; description containing unquoted colon-bearing text; copy-pasting frontmatter with tabs; editing with a tool that mangles the `---` fences; passing content with no frontmatter at all.","solutions":["Validate the YAML between the --- fences with a YAML linter/parser; fix indentation (spaces only, no tabs)","Quote the `description:` and `compatibility:` values (or use block scalars | >) when they contain colons or special characters","Ensure the file starts with `---`, has a closing `---`, and fields match the Skill schema (name, description, etc.)"],"exampleFix":"// before\n// description: Use when: user asks for tests\n// after\n// description: \"Use when: user asks for tests\"","handlingStrategy":"try-catch","validationCode":"func hasFrontmatter(content string) bool {\n\tlines := strings.SplitN(content, \"\\n\", 2)\n\tif len(lines) == 0 || strings.TrimSpace(lines[0]) != \"---\" {\n\t\treturn false\n\t}\n\t_, rest, ok := strings.Cut(content[4:], \"\\n---\")\n\treturn ok && strings.TrimSpace(rest) != \"\"\n}","typeGuard":null,"tryCatchPattern":"skill, err := skills.ParseContent(content)\nif err != nil {\n\tvar skipped *fs.PathError\n\tif errors.As(err, &skipped) {\n\t\treturn fmt.Errorf(\"unreadable skill file: %w\", err)\n\t}\n\treturn fmt.Errorf(\"invalid SKILL.md (check YAML frontmatter syntax, indentation, and --- fences): %w\", err)\n}","preventionTips":["Quote description/compatibility values containing colons or special YAML characters","Use spaces, never tabs, for frontmatter indentation","Verify the file begins with --- and has a matching closing --- fence","Run SKILL.md files through a YAML linter in CI"],"tags":["yaml","frontmatter","parsing","skills"],"backgroundTag":"yaml-frontmatter-parse-error","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}