sipeed/picoclaw · error

skill frontmatter name is required

Error message

skill frontmatter name is required

What it means

After splitting and parsing the frontmatter, validateAppliedSkillBody requires a non-empty trimmed value for the `name` field. The error means `name` is absent, null, empty, or whitespace-only in the frontmatter block. (A follow-on check, not this error, enforces that name matches the target skill.)

Source

Thrown at pkg/evolution/apply.go:161

	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
}

func allowsExistingFrontmatterFields(kind ChangeKind, hadOriginal bool) bool {
	return hadOriginal && (kind == ChangeKindAppend || kind == ChangeKindMerge)
}

func renderAppliedBody(draft SkillDraft, existingBody string, hadOriginal bool) (string, error) {
	switch draft.ChangeKind {
	case ChangeKindCreate:
		if hadOriginal {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Add `name: <exact target skill name>` as a top-level (column-0) frontmatter key
  2. If the value contains special YAML characters, quote it: name: "my-skill:v2"
  3. Check the key spelling and that it is not indented (must sit at column 0 within the block)
  4. Validate locally by parsing the frontmatter and asserting a non-blank name before applying

Example fix

# before
---
description: Deploys the app
---
# Deploy
...

# after
---
name: deploy
description: Deploys the app
---
# Deploy
...
Defensive patterns

Strategy: validation

Validate before calling

func frontmatterNamePresent(body string) bool {
    b := strings.TrimSpace(body)
    if !strings.HasPrefix(b, "---\n") {
        return false
    }
    rest := strings.TrimPrefix(b, "---\n")
    end := strings.Index(rest, "\n---")
    if end < 0 {
        return false
    }
    for _, line := range strings.Split(rest[:end], "\n") {
        if v, ok := strings.CutPrefix(line, "name:"); ok {
            return strings.TrimSpace(v) != ""
        }
    }
    return false
}

Try / catch

if err := apply.Change(body); err != nil {
    if strings.Contains(err.Error(), "skill frontmatter name is required") {
        return fmt.Errorf("add 'name: <target-skill>' to the frontmatter block: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Applying a skill whose frontmatter has only description (---\ndescription: x\n---); `name:` with no value or `name: ""`; name written with a tab indent so the field parser does not recognize the key; name key misspelled (Name:, title:) so fields["name"] is never set.

Common situations: Hand-written frontmatter omitting name because the filename seems sufficient; YAML copied from another tool using a different key; indentation errors from mixing tabs and spaces; LLM-generated frontmatter dropping fields.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/2fd02ed80b667b23. Report an issue: GitHub.