sipeed/picoclaw · error

skill patch frontmatter name %q does not match target skill

Error message

skill patch frontmatter name %q does not match target skill %q

What it means

renderDeployablePatchBody (pkg/evolution/apply.go:228) strips frontmatter from append/merge patch bodies; if the patch carries a `name` it must equal the target skill or be omitted entirely. Unlike the full-body check (where name is required and must match), the patch name is optional but must not disagree — a disagreeing patch header means the patch was written for a different skill.

Source

Thrown at pkg/evolution/apply.go:228

		}, "\n")
		return strings.TrimRight(existingBody, "\n") + mergedSection, nil
	default:
		return "", fmt.Errorf("unsupported change_kind %q", draft.ChangeKind)
	}
}

func renderDeployablePatchBody(body, targetSkillName string) (string, error) {
	body = renderDeployableSkillBody(body)
	frontmatter, markdownBody := splitSkillFrontmatter(body)
	if frontmatter == "" {
		markdownBody = body
	} else {
		fields, err := parseSkillFrontmatterFields(frontmatter, true)
		if err != nil {
			return "", err
		}
		if name := strings.TrimSpace(fields["name"]); name != "" && name != targetSkillName {
			return "", fmt.Errorf(
				"skill patch frontmatter name %q does not match target skill %q",
				name,
				targetSkillName,
			)
		}
	}
	return strings.TrimSpace(stripLeadingH1(markdownBody)), nil
}

func splitSkillFrontmatter(body string) (frontmatter, markdownBody string) {
	normalized := strings.ReplaceAll(strings.TrimSpace(body), "\r\n", "\n")
	lines := strings.Split(normalized, "\n")
	if len(lines) == 0 || strings.TrimSpace(lines[0]) != "---" {
		return "", body
	}
	end := -1
	for i := 1; i < len(lines); i++ {
		if strings.TrimSpace(lines[i]) == "---" {

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Remove the `name:` key from the patch frontmatter (it is stripped during rendering anyway)
  2. Or set the patch frontmatter name to exactly draft.TargetSkillName
  3. Regenerate the patch without copying source-skill frontmatter

Example fix

// before (append patch)
---
name: source-skill
description: ...
---
## New section

// after
## New section
Defensive patterns

Strategy: validation

Validate before calling

func patchNameAgrees(body, target string) error {
	// reuse frontmatter extraction; only fail when a name is present AND different
	var fm struct {
		Name string `yaml:"name"`
	}
	if fmBlock := extractFrontmatter(body); fmBlock != "" {
		if err := yaml.Unmarshal([]byte(fmBlock), &fm); err == nil {
			if n := strings.TrimSpace(fm.Name); n != "" && n != target {
				return fmt.Errorf("patch name %q != target %q", n, target)
			}
	}
	return nil
}

Try / catch

if err := applier.ApplyDraft(ctx, ws, draft); err != nil {
	if strings.Contains(err.Error(), "skill patch frontmatter name") {
		// drop or correct the name key in the patch frontmatter
	}
}

Prevention

When it happens

Trigger: Append/merge draft whose BodyOrPatch frontmatter declares `name: other-skill` while TargetSkillName differs — typically a patch excerpted from another skill's SKILL.md with its frontmatter left in, or an LLM echoing the source skill's name into the patch header.

Common situations: Shortcut/merge drafts assembled by copying sections of existing skill files; copy-paste patch authoring; generator prompts that include example frontmatter from a differently-named skill.

Related errors


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