{"record":{"id":"01c0d61dc3d1e6ec","repo":"FiloSottile/age","slug":"invalid-identity-encoding-v","errorCode":null,"errorMessage":"invalid identity encoding: %v","messagePattern":"invalid identity encoding: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/encode.go","lineNumber":32,"sourceCode":"\t\"filippo.io/hpke\"\n)\n\n// EncodeIdentity encodes a plugin identity string for a plugin with the given\n// name. If the name is invalid, it returns an empty string.\nfunc EncodeIdentity(name string, data []byte) string {\n\tif !validPluginName(name) {\n\t\treturn \"\"\n\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}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/plugin/encode.go#L14-L50","documentation":"ParseIdentity decodes a plugin identity string, which must be a bech32 string whose HRP starts with AGE-PLUGIN- and ends with '-'. This error means the input isn't valid bech32 at all, and it wraps the underlying bech32 decoder error for context.","triggerScenarios":"Passing a string that is not bech32 (truncated, wrong checksum, invalid characters, lowercase/uppercase mixing beyond HRP rules, or a completely different format like a raw file path) to ParseIdentity, directly or via NewIdentity/IdentityV1 when parsing AGE-PLUGIN-... identity files.","commonSituations":"Identity file contains a recipient string instead of an identity, or vice versa; file was truncated by copy/paste or a bad transfer; user pasted a key from a different tool (SSH key, age1... recipient); trailing newline/whitespace not trimmed before parsing.","solutions":["Check the identity file contains a full AGE-PLUGIN-XXXX-1... bech32 string with no truncation or stray whitespace (strings.TrimSpace before parsing)","Confirm you're using an identity string, not an age1... recipient — they are not interchangeable","Regenerate or re-export the identity from the plugin tool; the string is likely corrupted","Read the wrapped %v bech32 error — it pinpoints checksum vs. charset vs. length problems"],"exampleFix":"// before\nname, data, err := plugin.ParseIdentity(strings.TrimSpace(maybeWithNewline + \"\"))\n// after\ns := strings.TrimSpace(rawIdentity)\nif s == \"\" || !strings.HasPrefix(strings.ToUpper(s), \"AGE-PLUGIN-\") {\n    return fmt.Errorf(\"not a plugin identity file\")\n}\nname, data, err := plugin.ParseIdentity(s)","handlingStrategy":"validation","validationCode":"func looksLikePluginIdentity(s string) bool {\n    s = strings.TrimSpace(s)\n    up := strings.ToUpper(s)\n    return strings.HasPrefix(up, \"AGE-PLUGIN-\") && strings.HasSuffix(up, \"-1\") && len(s) > len(\"AGE-PLUGIN--1\")\n}\n// call before ParseIdentity","typeGuard":"func isPluginIdentity(s string) bool {\n    _, _, err := plugin.ParseIdentity(strings.TrimSpace(s))\n    return err == nil\n}","tryCatchPattern":"name, data, err := plugin.ParseIdentity(s)\nif err != nil {\n    return fmt.Errorf(\"identity file is not a valid plugin identity (bech32 decode failed): %w\", err)\n}","preventionTips":["Trim whitespace/newlines from identity strings before parsing","Distinguish identity (AGE-PLUGIN-...) from recipient (age1...) files","Validate identity strings at config-load time, not at decrypt time","Regenerate identities that fail bech32 decoding rather than patching them by hand"],"tags":["go","age","bech32","identity-parsing","input-validation"],"backgroundTag":"invalid-identity-encoding","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}