FiloSottile/age · error

malformed confirm stanza: unexpected number of arguments

Error message

malformed confirm stanza: unexpected number of arguments

What it means

In the client's plugin UI handler, a "confirm" stanza from the plugin must carry exactly one or two arguments (the YES option and optionally the NO option, bech32-encoded). A different argument count is rejected as malformed per the age-plugin protocol spec.

Source

Thrown at plugin/client.go:360

		if c.DisplayMessage == nil {
			return true, writeStanza(conn, "fail")
		}
		if err := c.DisplayMessage(name, string(s.Body)); err != nil {
			return true, writeStanza(conn, "fail")
		}
		return true, writeStanza(conn, "ok")
	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")

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Fix the plugin to send the confirm stanza with exactly one argument (YES) or two (YES and NO), each bech32-encoded
  2. Update the plugin to a spec-conforming release
  3. Inspect the plugin's stanza output (enable debugging or run it manually) to see the malformed argument list

Example fix

// before (plugin side)
writeStanzaWithBody(w, "confirm", "yes", "no", "maybe", message)
// after
writeStanzaWithBody(w, "confirm", bech32Encode("yes"), bech32Encode("no"), message)
Defensive patterns

Strategy: validation

Validate before calling

// Plugin-side pre-check before emitting confirm
if len(args) < 1 || len(args) > 2 { return errors.New("confirm needs 1 or 2 bech32 args") }

Try / catch

if err := unwrapWithPlugin(); err != nil && strings.Contains(err.Error(), "malformed confirm stanza") {
    return fmt.Errorf("plugin %s has a broken confirm implementation; upgrade it", pluginName)
}

Prevention

When it happens

Trigger: A plugin calls ui.Confirm with its protocol message built incorrectly — e.g. sending a confirm stanza with zero arguments or three or more — while the client's Unwrap is dispatching stanzas to handle().

Common situations: Custom plugin authors passing empty/extra arguments when emitting the confirm stanza; plugin versions incompatible with the client's protocol implementation.

Understand the failure class

Related errors


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