sipeed/picoclaw · error
unsupported change_kind %q
Error message
unsupported change_kind %q
What it means
renderAppliedBody's switch default (pkg/evolution/apply.go:213): draft.ChangeKind is not one of the four supported constants ("create", "append", "replace", "merge" from types.go). The Go zero value "" also lands here, so an unset ChangeKind is rejected rather than defaulted.
Source
Thrown at pkg/evolution/apply.go:213
}
return strings.TrimRight(existingBody, "\n") + "\n\n" + strings.TrimLeft(patch, "\n"), nil
case ChangeKindMerge:
patch, err := renderDeployablePatchBody(draft.BodyOrPatch, draft.TargetSkillName)
if err != nil {
return "", err
}
if !hadOriginal || strings.TrimSpace(existingBody) == "" {
return renderDeployableSkillBody(draft.BodyOrPatch), nil
}
mergedSection := strings.Join([]string{
"",
"## Merged Knowledge",
strings.TrimSpace(patch),
"",
}, "\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,View on GitHub (pinned to 49183d7e8d)
Solutions
- Set ChangeKind to evolution.ChangeKindCreate / Append / Replace / Merge exactly
- Validate ChangeKind against the four constants before calling ApplyDraft
- Purge or re-save stale drafts in skill_drafts.json after upgrading or downgrading
- Reject unknown change_kind values at draft load time
Example fix
// before
draft := evolution.SkillDraft{TargetSkillName: "x", BodyOrPatch: body} // ChangeKind == ""
// after
draft := evolution.SkillDraft{TargetSkillName: "x", BodyOrPatch: body, ChangeKind: evolution.ChangeKindCreate} Defensive patterns
Strategy: validation
Validate before calling
func supportedChangeKind(k evolution.ChangeKind) bool {
switch k {
case evolution.ChangeKindCreate, evolution.ChangeKindAppend,
evolution.ChangeKindReplace, evolution.ChangeKindMerge:
return true
}
return false
}
if !supportedChangeKind(draft.ChangeKind) {
// reject or default before calling ApplyDraft Type guard
func isValidChangeKind(k evolution.ChangeKind) bool {
switch k {
case evolution.ChangeKindCreate, evolution.ChangeKindAppend,
evolution.ChangeKindReplace, evolution.ChangeKindMerge:
return true
}
return false
} Try / catch
if err := applier.ApplyDraft(ctx, ws, draft); err != nil {
if strings.Contains(err.Error(), "unsupported change_kind") {
// draft came from a newer/older store — re-save or drop it
}
} Prevention
- Always set ChangeKind from the exported constants; never construct the string by hand
- Validate change_kind when loading drafts from JSON and reject unknown values at load time
- After version upgrades, purge drafts whose kinds the current binary does not recognize
When it happens
Trigger: A SkillDraft constructed without setting ChangeKind (zero value ""); ChangeKind loaded from the persisted drafts store (skill_drafts.json) with a typo'd or new value such as "update" or "Create"; drafts written by a newer package version using a kind this binary does not know.
Common situations: Hand-built drafts in tests or tools forgetting the field; version skew between the writer and reader of the drafts store; serialized enum renamed across releases.
Related errors
- no models available
- failed to get WeCom QR code: response missing scode or auth_
- WeCom QR scan succeeded but bot credentials are missing
- invalid WeCom QR generate URL: %w
- invalid WeCom QR query URL: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/ec4128a52fe19756.
Report an issue: GitHub.