{"record":{"id":"c16f94854a7b3ab7","repo":"FiloSottile/age","slug":"malformed-recipient-q-v","errorCode":null,"errorMessage":"malformed recipient %q: %v","messagePattern":"malformed recipient %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tag/tag.go","lineNumber":46,"sourceCode":")\n\n// Recipient is a tagged P-256 or hybrid P-256 + ML-KEM-768 recipient.\n//\n// The latter recipient is safe against future cryptographically-relevant\n// quantum computers, and can only be used along with other post-quantum\n// recipients.\ntype Recipient struct {\n\tpk hpke.PublicKey\n}\n\nvar _ age.Recipient = &Recipient{}\n\n// ParseRecipient returns a new [Recipient] from a Bech32 public key\n// encoding with the \"age1tag1\" or \"age1tagpq1\" prefix.\nfunc ParseRecipient(s string) (*Recipient, error) {\n\tt, k, err := plugin.ParseRecipient(s)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"malformed recipient %q: %v\", s, err)\n\t}\n\tswitch t {\n\tcase \"tag\":\n\t\tr, err := NewClassicRecipient(k)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"malformed recipient %q: %v\", s, err)\n\t\t}\n\t\treturn r, nil\n\tcase \"tagpq\":\n\t\tr, err := NewHybridRecipient(k)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"malformed recipient %q: %v\", s, err)\n\t\t}\n\t\treturn r, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"malformed recipient %q: invalid type %q\", s, t)\n\t}\n}","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/tag/tag.go#L28-L64","documentation":"tag.ParseRecipient decodes a Bech32 public key string with prefix \"age1tag1\" (or \"age1tagpq1\") using plugin.ParseRecipient. This error wraps a failure of that low-level parsing step — the string is not valid Bech32, has the wrong HRP/prefix, or fails plugin-level parsing — so no Recipient can be constructed from it.","triggerScenarios":"Calling tag.ParseRecipient(s) where s fails plugin.ParseRecipient: invalid Bech32 checksum, wrong HRP (not the expected age/tag prefix), mixed case, or invalid characters.","commonSituations":"Users pasting an X25519 age1... key instead of a tag recipient; truncated or hand-edited recipient strings; copy/paste introducing whitespace or case changes; confusing age1tag1 with age1tagpq1 keys.","solutions":["Check the wrapped %v for the exact Bech32/plugin parse failure (bad checksum, bad HRP, bad character).","Verify the string starts with the correct prefix (age1tag1 for classic, age1tagpq1 for hybrid) and is unmodified.","Regenerate or re-export the recipient string from the key holder rather than retyping it.","Strip whitespace/newlines and keep the original casing before parsing."],"exampleFix":"// before\nr, err := tag.ParseRecipient(strings.TrimSpace(userInput) + \"\")\n// after\ns := strings.TrimSpace(userInput)\nif !strings.HasPrefix(s, \"age1tag1\") && !strings.HasPrefix(s, \"age1tagpq1\") {\n    return fmt.Errorf(\"not a tag recipient: %s\", s)\n}\nr, err := tag.ParseRecipient(s)","handlingStrategy":"validation","validationCode":"func looksLikeTagRecipient(s string) bool {\n    s = strings.TrimSpace(s)\n    return strings.HasPrefix(s, \"age1tag1\") || strings.HasPrefix(s, \"age1tagpq1\")\n}\nif !looksLikeTagRecipient(userInput) {\n    return errors.New(\"not a tag recipient\")\n}\nr, err := tag.ParseRecipient(userInput)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the age1tag1/age1tagpq1 prefix before parsing.","Trim whitespace and reject hand-edited recipient strings.","Copy recipient strings verbatim from the key holder's export output."],"tags":["go","bech32","parsing","recipient"],"backgroundTag":"invalid-bech32-encoding","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}