FiloSottile/age · error
invalid plugin name: %q
Error message
invalid plugin name: %q
What it means
After decoding and validating the AGE-PLUGIN- prefix, ParseIdentity extracts the plugin name and validates it with validPluginName. If the extracted name is empty or contains characters outside the allowed set, the library rejects it because the name must be usable to invoke age-plugin-<name> on PATH.
Source
Thrown at plugin/encode.go:40
}
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
}
// ParseRecipient decodes a plugin recipient string. It returns the plugin name
// in lowercase and the encoded data.
func ParseRecipient(s string) (name string, data []byte, err error) {
hrp, data, err := bech32.Decode(s)View on GitHub (pinned to b74dce4cdb)
Solutions
- Print the extracted name (strings between AGE-PLUGIN- and trailing -) and check it against validPluginName rules (lowercase alphanumeric with allowed separators).
- Fix the plugin identity by re-encoding it with plugin.EncodeIdentity using a valid name.
- Use the exact name of an installed age-plugin-<name> binary.
- Regenerate the identity if the original is corrupt.
Example fix
// before
id, err := plugin.ParseIdentity("AGE-PLUGIN-MY_PLUGIN-1QQQ...") // '_' invalid
// after
id, err := plugin.ParseIdentity("AGE-PLUGIN-MY-PLUGIN-1QQQ...") Defensive patterns
Strategy: validation
Validate before calling
name := strings.TrimSuffix(strings.TrimPrefix(hrpGuess, "AGE-PLUGIN-"), "-")
if name == "" { reject() } // then validate charset Type guard
func validName(s string) bool {
if s == "" { return false }
for _, r := range s {
ok := r == '-' || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')
if !ok { return false }
}
return true
} Try / catch
name, data, err := plugin.ParseIdentity(s)
if err != nil {
return fmt.Errorf("identity %q rejected: %w", s, err)
} Prevention
- Only use lowercase names matching the plugin binary suffix
- Regenerate identities with plugin.EncodeIdentity rather than editing
- Validate names at config-load time
When it happens
Trigger: ParseIdentity called with a string like 'AGE-PLUGIN--1QQ...' (empty name) or whose name contains invalid characters (uppercase beyond case normalization, spaces, punctuation, non-ASCII) after lowercasing.
Common situations: Hand-crafted plugin strings from documentation typos; plugin binaries renamed with characters the name grammar forbids; truncated strings leaving an empty name; mixing separators like '_' instead of the allowed characters.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid plugin name: %q
- invalid encrypted payload size: %d
- invalid plugin name: %q
- not a plugin identity: %v
- invalid recipient encoding: %v
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/9c68436ff04a3682.
Report an issue: GitHub.