FiloSottile/age · error
not a plugin identity: %v
Error message
not a plugin identity: %v
What it means
ParseIdentity decodes a bech32 string and requires the human-readable part to start with 'AGE-PLUGIN-' and end with '-'. If the prefix/suffix check fails, the library rejects the string as not being a plugin identity encoding. This guards against passing native age identities (e.g. AGE-SECRET-KEY-...) or arbitrary strings to the plugin API.
Source
Thrown at plugin/encode.go:35
// EncodeIdentity encodes a plugin identity string for a plugin with the given
// name. If the name is invalid, it returns an empty string.
func EncodeIdentity(name string, data []byte) string {
if !validPluginName(name) {
return ""
}
s, _ := bech32.Encode("AGE-PLUGIN-"+strings.ToUpper(name)+"-", data)
return s
}
// ParseIdentity decodes a plugin identity string. It returns the plugin name
// in lowercase and the encoded data.
func ParseIdentity(s string) (name string, data []byte, err error) {
hrp, data, err := bech32.Decode(s)
if err != nil {
return "", nil, fmt.Errorf("invalid identity encoding: %v", err)
}
if !strings.HasPrefix(hrp, "AGE-PLUGIN-") || !strings.HasSuffix(hrp, "-") {
return "", nil, fmt.Errorf("not a plugin identity: %v", err)
}
name = strings.TrimSuffix(strings.TrimPrefix(hrp, "AGE-PLUGIN-"), "-")
name = strings.ToLower(name)
if !validPluginName(name) {
return "", nil, fmt.Errorf("invalid plugin name: %q", name)
}
return name, data, nil
}
// EncodeRecipient encodes a plugin recipient string for a plugin with the given
// name. If the name is invalid, it returns an empty string.
func EncodeRecipient(name string, data []byte) string {
if !validPluginName(name) {
return ""
}
s, _ := bech32.Encode("age1"+strings.ToLower(name), data)
return s
}View on GitHub (pinned to b74dce4cdb)
Solutions
- Verify the string is a plugin identity: it must be bech32 and its hrp must match AGE-PLUGIN-<name>- exactly.
- If it is a native age identity (AGE-SECRET-KEY-...), parse it with the age/crypto package instead of the plugin package.
- Restore the trailing '-' if the string was truncated.
- Call ParseIdentity only on identity strings produced by EncodeIdentity or the plugin itself.
Example fix
// before
name, data, err := plugin.ParseIdentity("AGE-SECRET-KEY-1QQQQ...")
// after
if strings.HasPrefix(idStr, "AGE-SECRET-KEY-") { /* use native age identity parser */ }
name, data, err := plugin.ParseIdentity("AGE-PLUGIN-FROOD-1QQQQ...") Defensive patterns
Strategy: validation
Validate before calling
func looksLikePluginIdentity(s string) bool {
hrp, _, err := bech32.Decode(s)
return err == nil && strings.HasPrefix(hrp, "AGE-PLUGIN-") && strings.HasSuffix(hrp, "-")
} Type guard
func isPluginIdentity(s string) bool { return looksLikePluginIdentity(s) } Try / catch
name, data, err := plugin.ParseIdentity(s)
if err != nil {
if strings.Contains(err.Error(), "not a plugin identity") { return fmt.Errorf("%q is not a plugin identity (expected AGE-PLUGIN-...)", s) }
return err
} Prevention
- Check for the AGE-PLUGIN- prefix and trailing '-' before parsing
- Use the native age identity parser for AGE-SECRET-KEY strings
- Never hand-edit plugin identity strings
- Store identities verbatim from EncodeIdentity output
When it happens
Trigger: Calling plugin.ParseIdentity (directly or via plugin.NewIdentity) with a bech32 string whose hrp is not AGE-PLUGIN-<name>- — e.g. a native 'AGE-SECRET-KEY-1...' identity, an 'age1...' recipient, or a plugin string missing the trailing dash.
Common situations: Developers confuse native age identity files with plugin identity strings; pass a recipient string where an identity is expected; hand-truncate or reformat a plugin identity losing the trailing '-'; paste strings from docs with wrong case for the hrp (bech32 hrp is lowercase, but the plugin convention uses AGE-PLUGIN-).
Related errors
- invalid recipient encoding: %v
- not a plugin recipient: %v
- malformed recipient %q: %v
- malformed confirm stanza: invalid YES option encoding
- malformed confirm stanza: invalid NO option encoding
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/48396603d47195d8.
Report an issue: GitHub.