FiloSottile/age · error

malformed confirm stanza: invalid YES option encoding

Error message

malformed confirm stanza: invalid YES option encoding

What it means

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.

Source

Thrown at plugin/client.go:367

	case "request-secret", "request-public":
		if c.RequestValue == nil {
			return true, writeStanza(conn, "fail")
		}
		secret, err := c.RequestValue(name, string(s.Body), s.Type == "request-secret")
		if err != nil {
			return true, writeStanza(conn, "fail")
		}
		return true, writeStanzaWithBody(conn, "ok", []byte(secret))
	case "confirm":
		if len(s.Args) != 1 && len(s.Args) != 2 {
			return true, fmt.Errorf("malformed confirm stanza: unexpected number of arguments")
		}
		if c.Confirm == nil {
			return true, writeStanza(conn, "fail")
		}
		yes, err := format.DecodeString(s.Args[0])
		if err != nil {
			return true, fmt.Errorf("malformed confirm stanza: invalid YES option encoding")
		}
		var no []byte
		if len(s.Args) == 2 {
			no, err = format.DecodeString(s.Args[1])
			if err != nil {
				return true, fmt.Errorf("malformed confirm stanza: invalid NO option encoding")
			}
		}
		choseYes, err := c.Confirm(name, string(s.Body), string(yes), string(no))
		if err != nil {
			return true, writeStanza(conn, "fail")
		}
		result := "yes"
		if !choseYes {
			result = "no"
		}
		return true, writeStanza(conn, "ok", result)
	default:

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Fix the plugin to bech32-encode the YES option, e.g. bech32.Encode("", []byte("yes"))
  2. Check for stray whitespace or uppercase/lowercase mixing that breaks bech32 checksums
  3. Update the plugin binary to a spec-conforming version

Example fix

// before (plugin side)
args := []string{"yes"}
// after
yes, _ := bech32.Encode("", []byte("yes"))
args := []string{yes}
Defensive patterns

Strategy: validation

Validate before calling

// Plugin-side: ensure encodability before sending
if _, err := bech32.Encode("", []byte("yes")); err != nil { return err }

Try / catch

if err := unwrap(); err != nil && strings.Contains(err.Error(), "invalid YES option encoding") {
    return fmt.Errorf("plugin confirm YES label is not bech32; upgrade plugin")
}

Prevention

When it happens

Trigger: Plugin sends "confirm" with YES option not bech32-encoded (raw plaintext, wrong charset, invalid checksum, or empty string) during Unwrap's stanza handling.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31). Data as JSON: /api/errors/acfb2b6d8e5730b9. Report an issue: GitHub.