FiloSottile/age · error

malformed recipient stanza: invalid index

Error message

malformed recipient stanza: invalid index

What it means

The plugin sent a recipient-stanza whose first argument (the file-key index) is not a valid decimal integer, so strconv.Atoi failed. The protocol requires Args[0] to be the numeric index of the wrapped file key; anything else is rejected as malformed.

Source

Thrown at plugin/client.go:121

	}

	// Phase 2: plugin responds with stanzas
	sr := format.NewStanzaReader(bufio.NewReader(conn))
ReadLoop:
	for {
		s, err := r.ui.readStanza(r.name, sr)
		if err != nil {
			return nil, nil, err
		}

		switch s.Type {
		case "recipient-stanza":
			if len(s.Args) < 2 {
				return nil, nil, fmt.Errorf("malformed recipient stanza: unexpected argument count")
			}
			n, err := strconv.Atoi(s.Args[0])
			if err != nil {
				return nil, nil, fmt.Errorf("malformed recipient stanza: invalid index")
			}
			// We only send a single file key, so the index must be 0.
			if n != 0 {
				return nil, nil, fmt.Errorf("malformed recipient stanza: unexpected index")
			}

			stanzas = append(stanzas, &age.Stanza{
				Type: s.Args[1],
				Args: s.Args[2:],
				Body: s.Body,
			})

			if err := writeStanza(conn, "ok"); err != nil {
				return nil, nil, err
			}
		case "labels":
			if labels != nil {
				return nil, nil, fmt.Errorf("repeated labels stanza")

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Upgrade the plugin to a version matching the current recipient-v1 protocol (numeric index as first arg).
  2. Fix the plugin's stanza writer so Args[0] is the decimal file-key index ('0' for a single file key).
  3. Capture the raw stanza to verify the argument layout before filing a bug with the plugin author.
  4. Pin known-good plugin versions to avoid mixing protocol revisions.

Example fix

// before (plugin side)
writeStanza(conn, "recipient-stanza", "x25519", body) // no index, type first
// after
writeStanza(conn, "recipient-stanza", "0", "x25519", body)
Defensive patterns

Strategy: validation

Validate before calling

// Go: ensure the index argument parses before use
if _, err := strconv.Atoi(args[0]); err != nil {
    return fmt.Errorf("plugin sent non-numeric stanza index %q", args[0])
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "invalid index") {
        return fmt.Errorf("plugin protocol mismatch (missing numeric index); upgrade plugin: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: WrapWithLabels/Wrap receives a recipient-stanza where Args[0] is a non-numeric string, e.g. the plugin omitted the index or put the stanza type first.

Common situations: Old or non-conformant plugin versions that send stanzas without the leading index; a plugin written against a different protocol revision; argument ordering bugs in a plugin under development.

Understand the failure class

Related errors


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