{"record":{"id":"3a92c3d67156d016","repo":"gravitational/teleport","slug":"multi-valued-rdn-must-refer-to-the-same-attribute","errorCode":null,"errorMessage":"multi-valued RDN must refer to the same attribute, but found %q instead of %q, remaining tokens: %s","messagePattern":"multi-valued RDN must refer to the same attribute, but found %q instead of %q, remaining tokens: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":109,"sourceCode":"\t}\n\t_ = markAttr(prevAttr)\n\n\tfor {\n\t\ttok, ok := tokens.Peek()\n\t\tif !ok {\n\t\t\treturn nil // end\n\t\t}\n\n\t\tswitch tok.kind {\n\t\tcase tokenPlus:\n\t\t\ttokens.PopSilently()\n\n\t\t\t// Validate that prevAttr == current attr.\n\t\t\t// If `!ok` just keep going and parseATV() will fail.\n\t\t\tif nextTok, ok := tokens.Peek(); ok &&\n\t\t\t\tnextTok.kind == tokenAttrType &&\n\t\t\t\tnextTok.value != prevAttr {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"multi-valued RDN must refer to the same attribute, but found %q instead of %q, remaining tokens: %s\",\n\t\t\t\t\tprevAttr,\n\t\t\t\t\tnextTok.value,\n\t\t\t\t\ttokens,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tprevAttr, err = parseATV(dst, tokens)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\tcase tokenComma:\n\t\t\ttokens.PopSilently()\n\t\t\tprevAttr, err = parseATV(dst, tokens)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L91-L127","documentation":"Multi-valued RDNs (components joined by '+') are only permitted when every value refers to the same attributeType (a parser deviation from RFC 2253 documented in ParseDistinguishedName). After seeing '+', parseRDNSequence peeks at the next attribute type and rejects it if it differs from the previous one in the current RDN.","triggerScenarios":"ParseDistinguishedName('CN=proxy+O=Teleport') — '+' joins CN and O, which are different attribute types, so the parser returns this error with both attribute names and remaining tokens in the message.","commonSituations":"Users copy real-world X.509 subjects like 'CN=Name+serialNumber=123' or 'OU=Unit1+O=Org' from certificates, assuming standard RFC 4514 multi-valued RDN semantics that this stricter parser does not allow.","solutions":["Replace the '+' with a ',' so each attribute becomes its own RDN — but then ensure the attribute type is not repeated (see duplicate-attribute error)","Drop one of the attributes if the differing one is not needed","Only use '+' to give multiple values of the SAME attribute, e.g. 'OU=TeamA+OU=TeamB'","Pre-validate that every '+'-joined component shares one attribute type"],"exampleFix":"// before\nParseDistinguishedName(\"CN=proxy+O=Teleport\")\n// after\nParseDistinguishedName(\"CN=proxy\") // or \"CN=proxy,O=Teleport\" if the duplicate rule allows","handlingStrategy":"validation","validationCode":"func multiRDNAttrsValid(dn string) error {\n\tfor _, rdn := range strings.Split(dn, \",\") {\n\t\tattrs := strings.Split(rdn, \"+\")\n\t\ttypes := map[string]bool{}\n\t\tfor _, a := range attrs {\n\t\t\tkv := strings.SplitN(strings.TrimSpace(a), \"=\", 2)\n\t\t\tif len(kv) == 2 { types[kv[0]] = true }\n\t\t}\n\t\tif len(types) > 1 { return fmt.Errorf(\"multi-valued RDN %q mixes attribute types\", rdn) }\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := multiRDNAttrsValid(dn); err != nil { return err }\nname, err := pkixname.ParseDistinguishedName(dn)\nif err != nil { return fmt.Errorf(\"invalid DN %q: %w\", dn, err) }","preventionTips":["Only use '+' to join multiple values of the SAME attribute type (e.g. 'OU=A+OU=B')","When porting DNs from other certificates, flatten mixed '+' RDNs into separate components where the duplicate rule allows","Treat this parser as stricter than RFC 4514 — read the documented deviations"],"tags":["x509","distinguished-name","parsing","rfc4514"],"backgroundTag":"multi-valued-rdn-mismatch","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}