FiloSottile/age · error

%s

Error message

%s

What it means

The plugin sent an 'error' stanza, indicating it failed on its side during the wrap protocol. The client surfaces the plugin's error body verbatim as the returned error, so this is the plugin's own failure message (device error, permission denial, unsupported recipient, etc.).

Source

Thrown at plugin/client.go:151

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

			if err := writeStanza(conn, "ok"); err != nil {
				return nil, nil, err
			}
		case "error":
			if err := writeStanza(conn, "ok"); err != nil {
				return nil, nil, err
			}

			return nil, nil, fmt.Errorf("%s", s.Body)
		case "done":
			break ReadLoop
		default:
			if ok, err := r.ui.handle(r.name, conn, s); err != nil {
				return nil, nil, err
			} else if !ok {
				if err := writeStanza(conn, "unsupported"); err != nil {
					return nil, nil, err
				}
			}
		}
	}

	if len(stanzas) == 0 {
		return nil, nil, fmt.Errorf("received zero recipient stanzas")
	}

	return stanzas, labels, nil

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Read the error body text (it is the plugin's message) and act on it directly.
  2. Verify the hardware/agent the plugin depends on is available and unlocked.
  3. Validate the recipient string format for that plugin using its own tooling.
  4. Update the plugin; if the message is an internal error, reproduce it with the plugin CLI and report upstream.

Example fix

// before
out, err := age.Wrap(...) // returns plugin body e.g. "yubikey: device not found"
// after
out, err := age.Wrap(...)
if err != nil {
    if strings.Contains(err.Error(), "device not found") {
        return fmt.Errorf("plug in the YubiKey and retry: %w", err)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: pre-check the device/agent the plugin depends on when possible
// e.g. run the plugin's own list/status command to verify the key is reachable

Try / catch

stanzas, labels, err := client.WrapWithLabels(fileKey)
if err != nil {
    body := strings.TrimSpace(err.Error()) // plugin's own error text
    if strings.Contains(body, "device not found") || strings.Contains(body, "PIN") {
        return fmt.Errorf("unlock/present the hardware token: %s", body)
    }
    return fmt.Errorf("plugin reported: %s", body)
}

Prevention

When it happens

Trigger: Calling WrapWithLabels/Wrap when the plugin starts successfully but responds with an 'error' stanza, e.g. a YubiKey plugin cannot reach the key, the smartcard is locked, or the recipient is unsupported by the plugin.

Common situations: Hardware token not present or locked (PIN retries exhausted); touch/agent confirmation required but not granted; plugin does not recognize the recipient string; plugin-side internal errors.

Related errors


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