{"record":{"id":"9c68436ff04a3682","repo":"FiloSottile/age","slug":"invalid-plugin-name-q-9c6843","errorCode":null,"errorMessage":"invalid plugin name: %q","messagePattern":"invalid plugin name: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/encode.go","lineNumber":40,"sourceCode":"\t}\n\ts, _ := bech32.Encode(\"AGE-PLUGIN-\"+strings.ToUpper(name)+\"-\", data)\n\treturn s\n}\n\n// ParseIdentity decodes a plugin identity string. It returns the plugin name\n// in lowercase and the encoded data.\nfunc ParseIdentity(s string) (name string, data []byte, err error) {\n\thrp, data, err := bech32.Decode(s)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"invalid identity encoding: %v\", err)\n\t}\n\tif !strings.HasPrefix(hrp, \"AGE-PLUGIN-\") || !strings.HasSuffix(hrp, \"-\") {\n\t\treturn \"\", nil, fmt.Errorf(\"not a plugin identity: %v\", err)\n\t}\n\tname = strings.TrimSuffix(strings.TrimPrefix(hrp, \"AGE-PLUGIN-\"), \"-\")\n\tname = strings.ToLower(name)\n\tif !validPluginName(name) {\n\t\treturn \"\", nil, fmt.Errorf(\"invalid plugin name: %q\", name)\n\t}\n\treturn name, data, nil\n}\n\n// EncodeRecipient encodes a plugin recipient string for a plugin with the given\n// name. If the name is invalid, it returns an empty string.\nfunc EncodeRecipient(name string, data []byte) string {\n\tif !validPluginName(name) {\n\t\treturn \"\"\n\t}\n\ts, _ := bech32.Encode(\"age1\"+strings.ToLower(name), data)\n\treturn s\n}\n\n// ParseRecipient decodes a plugin recipient string. It returns the plugin name\n// in lowercase and the encoded data.\nfunc ParseRecipient(s string) (name string, data []byte, err error) {\n\thrp, data, err := bech32.Decode(s)","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/plugin/encode.go#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nid, err := plugin.ParseIdentity(\"AGE-PLUGIN-MY_PLUGIN-1QQQ...\") // '_' invalid\n// after\nid, err := plugin.ParseIdentity(\"AGE-PLUGIN-MY-PLUGIN-1QQQ...\")","handlingStrategy":"validation","validationCode":"name := strings.TrimSuffix(strings.TrimPrefix(hrpGuess, \"AGE-PLUGIN-\"), \"-\")\nif name == \"\" { reject() } // then validate charset","typeGuard":"func validName(s string) bool {\n\tif s == \"\" { return false }\n\tfor _, r := range s {\n\t\tok := r == '-' || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')\n\t\tif !ok { return false }\n\t}\n\treturn true\n}","tryCatchPattern":"name, data, err := plugin.ParseIdentity(s)\nif err != nil {\n\treturn fmt.Errorf(\"identity %q rejected: %w\", s, err)\n}","preventionTips":["Only use lowercase names matching the plugin binary suffix","Regenerate identities with plugin.EncodeIdentity rather than editing","Validate names at config-load time"],"tags":["go","validation","naming","age-encryption"],"backgroundTag":"schema-validation-failed","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}