{"record":{"id":"21ef32aec501513d","repo":"FiloSottile/age","slug":"labels-q-do-not-match-previous-recipients-q","errorCode":null,"errorMessage":"labels %q do not match previous recipients %q","messagePattern":"labels %q do not match previous recipients %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/plugin.go","lineNumber":367,"sourceCode":"\t}\n\n\tif err := writeStanza(p.stdout, \"done\"); err != nil {\n\t\treturn p.fatalf(\"failed to write done stanza: %v\", err)\n\t}\n\treturn 0\n}\n\nfunc wrapWithLabels(r age.Recipient, fileKey []byte) ([]*age.Stanza, []string, error) {\n\tif r, ok := r.(age.RecipientWithLabels); ok {\n\t\treturn r.WrapWithLabels(fileKey)\n\t}\n\ts, err := r.Wrap(fileKey)\n\treturn s, nil, err\n}\n\nfunc checkLabels(ll, labels []string) error {\n\tif !slices.Equal(ll, labels) {\n\t\treturn fmt.Errorf(\"labels %q do not match previous recipients %q\", ll, labels)\n\t}\n\treturn nil\n}\n\n// IdentityV1 implements the identity-v1 state machine. It returns an exit code\n// to pass to os.Exit.\n//\n// Most plugins should call [Plugin.Main] instead of this method.\nfunc (p *Plugin) IdentityV1() int {\n\tif p.identity == nil {\n\t\treturn p.fatalf(\"identity-v1 not supported\")\n\t}\n\n\tvar files [][]*age.Stanza\n\tvar identityStrings []string\n\n\tp.sr = format.NewStanzaReader(bufio.NewReader(p.stdin))\nReadLoop:","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/plugin/plugin.go#L349-L385","documentation":"checkLabels verifies that all recipients produced by this plugin declare the same stanza label set as previously generated recipients for the same file key. age requires every stanza for a file key to carry consistent labels, so a plugin returning recipients with differing labels fails the whole wrap operation.","triggerScenarios":"The plugin's Recipient.Wrap returns stanzas whose Labels() differ between multiple recipients for one file key; a recipient nondeterministically returns different label sets (e.g. conditional labels based on state or randomness).","commonSituations":"A custom plugin whose Wrap emits an extra label (e.g. \"postprompt\") for some recipients but not others; mixing an old and new recipient type inside one plugin.","solutions":["Make the plugin's Recipient return a fixed, deterministic label set for every recipient instance","Remove conditional label logic so all recipients from the plugin declare identical labels","Align the labels with the plugin spec's required label list for that plugin type"],"exampleFix":"// before\nfunc (r *plugRecipient) Labels() []string {\n    if r.legacy { return []string{\"postprompt\"} }\n    return nil\n}\n// after\nfunc (r *plugRecipient) Labels() []string { return []string{\"postprompt\"} }","handlingStrategy":"validation","validationCode":"// In the plugin, unit-test label consistency across recipients:\nlabels := r1.Labels()\nfor _, r := range []Recipient{r1, r2, r3} {\n    if !slices.Equal(r.Labels(), labels) {\n        t.Fatalf(\"inconsistent labels: %v vs %v\", r.Labels(), labels)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Return a constant label set from every recipient implementation","Add regression tests comparing Labels() across recipient variants","Never derive labels from per-instance state"],"tags":["age","plugin","labels","protocol"],"backgroundTag":"stanza-labels-mismatch","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}