{"record":{"id":"acfb2b6d8e5730b9","repo":"FiloSottile/age","slug":"malformed-confirm-stanza-invalid-yes-option-encod","errorCode":null,"errorMessage":"malformed confirm stanza: invalid YES option encoding","messagePattern":"malformed confirm stanza: invalid YES option encoding","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/client.go","lineNumber":367,"sourceCode":"\tcase \"request-secret\", \"request-public\":\n\t\tif c.RequestValue == nil {\n\t\t\treturn true, writeStanza(conn, \"fail\")\n\t\t}\n\t\tsecret, err := c.RequestValue(name, string(s.Body), s.Type == \"request-secret\")\n\t\tif err != nil {\n\t\t\treturn true, writeStanza(conn, \"fail\")\n\t\t}\n\t\treturn true, writeStanzaWithBody(conn, \"ok\", []byte(secret))\n\tcase \"confirm\":\n\t\tif len(s.Args) != 1 && len(s.Args) != 2 {\n\t\t\treturn true, fmt.Errorf(\"malformed confirm stanza: unexpected number of arguments\")\n\t\t}\n\t\tif c.Confirm == nil {\n\t\t\treturn true, writeStanza(conn, \"fail\")\n\t\t}\n\t\tyes, err := format.DecodeString(s.Args[0])\n\t\tif err != nil {\n\t\t\treturn true, fmt.Errorf(\"malformed confirm stanza: invalid YES option encoding\")\n\t\t}\n\t\tvar no []byte\n\t\tif len(s.Args) == 2 {\n\t\t\tno, err = format.DecodeString(s.Args[1])\n\t\t\tif err != nil {\n\t\t\t\treturn true, fmt.Errorf(\"malformed confirm stanza: invalid NO option encoding\")\n\t\t\t}\n\t\t}\n\t\tchoseYes, err := c.Confirm(name, string(s.Body), string(yes), string(no))\n\t\tif err != nil {\n\t\t\treturn true, writeStanza(conn, \"fail\")\n\t\t}\n\t\tresult := \"yes\"\n\t\tif !choseYes {\n\t\t\tresult = \"no\"\n\t\t}\n\t\treturn true, writeStanza(conn, \"ok\", result)\n\tdefault:","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/plugin/client.go#L349-L385","documentation":"The confirm stanza's YES option argument could not be decoded as bech32 (format.DecodeString failed). The protocol requires both confirm options to be bech32-encoded strings, so the client rejects undecodable YES values.","triggerScenarios":"Plugin sends \"confirm\" with YES option not bech32-encoded (raw plaintext, wrong charset, invalid checksum, or empty string) during Unwrap's stanza handling.","commonSituations":"Plugin authors forgetting to bech32-encode the button labels; encoding with a different HRP/case convention than format.DecodeString accepts; hand-written protocol code using base64 instead of bech32.","solutions":["Fix the plugin to bech32-encode the YES option, e.g. bech32.Encode(\"\", []byte(\"yes\"))","Check for stray whitespace or uppercase/lowercase mixing that breaks bech32 checksums","Update the plugin binary to a spec-conforming version"],"exampleFix":"// before (plugin side)\nargs := []string{\"yes\"}\n// after\nyes, _ := bech32.Encode(\"\", []byte(\"yes\"))\nargs := []string{yes}","handlingStrategy":"validation","validationCode":"// Plugin-side: ensure encodability before sending\nif _, err := bech32.Encode(\"\", []byte(\"yes\")); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := unwrap(); err != nil && strings.Contains(err.Error(), \"invalid YES option encoding\") {\n    return fmt.Errorf(\"plugin confirm YES label is not bech32; upgrade plugin\")\n}","preventionTips":["Always bech32-encode confirm labels; never send raw strings","Avoid mixed case and invalid bech32 characters in labels","Compare against a known-good plugin's confirm output"],"tags":["go","age","plugin-protocol","bech32","confirm-stanza"],"backgroundTag":"plugin-protocol-violation","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}