sipeed/picoclaw · error
skill heading is required
Error message
skill heading is required
What it means
validateAppliedSkillBody requires the skill body to contain a line-anchored H1: the literal substring "\n# ". Frontmatter alone is not enough - the body must also carry an ATX H1 heading (which becomes the skill document's title). Note the check: '## Subheading' does not match, '#Heading' without a space does not match, and a heading is found only when preceded by a newline (the frontmatter's closing '---' line supplies one).
Source
Thrown at pkg/evolution/apply.go:152
return err
}
return nil
}
func isDirNotEmptyError(err error) bool {
if err == nil {
return false
}
return strings.Contains(strings.ToLower(err.Error()), "directory not empty")
}
func validateAppliedSkillBody(body, targetSkillName string, allowExtraFrontmatterFields bool) error {
body = strings.TrimSpace(body)
if !strings.HasPrefix(body, "---\n") {
return fmt.Errorf("skill frontmatter is required")
}
if !strings.Contains(body, "\n# ") {
return fmt.Errorf("skill heading is required")
}
frontmatter, _ := splitSkillFrontmatter(body)
fields, err := parseSkillFrontmatterFields(frontmatter, allowExtraFrontmatterFields)
if err != nil {
return err
}
name := strings.TrimSpace(fields["name"])
if name == "" {
return fmt.Errorf("skill frontmatter name is required")
}
if name != targetSkillName {
return fmt.Errorf("skill frontmatter name %q does not match target skill %q", name, targetSkillName)
}
if strings.TrimSpace(fields["description"]) == "" {
return fmt.Errorf("skill frontmatter description is required")
}
return nil
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Add an H1 line after the frontmatter, e.g. '# Skill Name' with a space after the hash
- If you only have '##' headings, promote the first one to '#'
- Verify locally: strings.Contains(body, "\\n# ") before applying
Example fix
# before: frontmatter + only H2 headings --- name: deploy description: Deploy the app --- ## Build ... ## Ship ... # after: H1 present --- name: deploy description: Deploy the app --- # Deploy ## Build ... ## Ship ...
Defensive patterns
Strategy: validation
Validate before calling
func hasH1(body string) bool {
return strings.Contains(strings.ReplaceAll(body, "\r\n", "\n"), "\n# ")
} Try / catch
if err := apply.Change(body); err != nil {
if strings.Contains(err.Error(), "skill heading is required") {
return fmt.Errorf("skill body needs a top-level '# ' heading: %w", err)
}
return err
} Prevention
- Give every skill doc exactly one H1 title line following the frontmatter
- Remember '## ' and '#NoSpace' do not satisfy the check - use '# ' with a space
- Include an H1 in skill templates so generated content inherits it
When it happens
Trigger: Applying a skill whose body is only frontmatter plus paragraphs or bullet lists; a body that uses only '##' subheadings; a heading written without a space after the hash ('#Title'); content where the only H1 was deleted during editing.
Common situations: Authors structuring skill docs purely with H2s; diff/patch tooling that strips what looks like a duplicate title; generated content from templates that omit the H1 when a title field exists in frontmatter.
Related errors
- skill frontmatter is required
- skill frontmatter name is required
- apply draft failed
- name is required
- description is required
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/bf567603fd77fe3b.
Report an issue: GitHub.