FiloSottile/age · error

recipient encodings not supported

Error message

recipient encodings not supported

What it means

RecipientV1 returns this when the plugin's Recipient field is nil, meaning the plugin binary does not implement a recipient-v1 encoding at all. The client sent recipient stanza(s), but this plugin was only built for identities (or nothing). The library cannot wrap the file key, so it fails fast with a per-recipient error naming the offending recipient index.

Source

Thrown at plugin/plugin.go:252

	if len(recipientStrings)+len(identityStrings) == 0 {
		return p.fatalf("no recipients or identities provided")
	}
	if len(fileKeys) == 0 {
		return p.fatalf("no file keys provided")
	}

	var recipients, identities []age.Recipient
	for i, s := range recipientStrings {
		name, data, err := ParseRecipient(s)
		if err != nil {
			return p.recipientError(i, err)
		}
		if name != p.name {
			return p.recipientError(i, fmt.Errorf("unsupported plugin name: %q", name))
		}
		if p.recipient == nil {
			return p.recipientError(i, fmt.Errorf("recipient encodings not supported"))
		}
		r, err := p.recipient(data)
		if err != nil {
			return p.recipientError(i, err)
		}
		recipients = append(recipients, r)
	}
	for i, s := range identityStrings {
		name, data, err := ParseIdentity(s)
		if err != nil {
			return p.identityError(i, err)
		}
		if name != p.name {
			return p.identityError(i, fmt.Errorf("unsupported plugin name: %q", name))
		}
		if p.idAsRecipient == nil {
			return p.identityError(i, fmt.Errorf("identity encodings not supported"))
		}

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Set the Plugin.Recipient callback in the plugin's main before calling RecipientV1
  2. Make the plugin's flag handling reject recipient mode when no Recipient encoding is implemented, with a clear usage message
  3. Update the plugin to a version that supports recipient encodings

Example fix

// before
p := plugin.New(name, nil, nil)
os.Exit(p.RecipientV1(os.Stdin, os.Stdout, os.Args...))
// after
p := plugin.New(name, func(data []byte) (age.Recipient, error) { return parseRecipient(data) }, nil)
os.Exit(p.RecipientV1(os.Stdin, os.Stdout, os.Args...))
Defensive patterns

Strategy: validation

Validate before calling

// In the plugin's main, before RecipientV1:
if p == nil || p.Recipient == nil {
    fmt.Fprintf(os.Stderr, "usage: %s does not support recipient encodings\n", os.Args[0])
    os.Exit(1)
}
// In the age client/integration, before invoking:
// out, _ := exec.Command(pluginPath, "--age-plugin=plugin-v1").Output(); strings.Contains(string(out), "recipient-v1")

Prevention

When it happens

Trigger: Running the plugin binary in RecipientV1 mode while the Plugin was constructed without setting Plugin.Recipient; e.g. an age-plugin binary compiled from a main that only registers Identity and calls RecipientV1 as part of generic dispatch.

Common situations: A plugin supporting only identity decryption (e.g. a hardware-token plugin) is passed as a -r recipient argument; a plugin refactor renamed the callback and left Recipient nil; wiring the wrong constructor so Recipient was never assigned.

Related errors


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