{"record":{"id":"f8a39537f8b4bf16","repo":"gravitational/teleport","slug":"repeated-attributetype-q-remaining-tokens-s","errorCode":null,"errorMessage":"repeated attributeType %q, remaining tokens: %s","messagePattern":"repeated attributeType %q, remaining tokens: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":82,"sourceCode":"\t}\n\n\tdst := &pkix.Name{}\n\tif tokens.Len() == 0 {\n\t\treturn dst, nil\n\t}\n\tif err := parseRDNSequence(dst, *tokens); err != nil {\n\t\treturn nil, fmt.Errorf(\"malformed RDNs: %w\", err)\n\t}\n\treturn dst, nil\n}\n\n// parseRDNSequence parses a RelativeDistinguishedName sequence, ie, a sequence\n// of AttributeTypeAndValue separated by commas or pluses.\nfunc parseRDNSequence(dst *pkix.Name, tokens tokenList) error {\n\tseenAttrs := make(map[string]struct{})\n\tmarkAttr := func(attr string) error {\n\t\tif _, ok := seenAttrs[attr]; ok {\n\t\t\treturn fmt.Errorf(\"repeated attributeType %q, remaining tokens: %s\", attr, tokens)\n\t\t}\n\t\tseenAttrs[attr] = struct{}{}\n\t\treturn nil\n\t}\n\n\tprevAttr, err := parseATV(dst, tokens)\n\tif err != nil {\n\t\treturn err\n\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 {","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L64-L100","documentation":"parseRDNSequence tracks attribute types already seen across comma-separated RDNs via seenAttrs. When the same attributeType appears twice in distinct RDNs (e.g. 'CN=a,CN=b'), markAttr returns this error. Multi-valued RDNs joined by '+' are allowed, but the same attribute may only appear once per comma-separated component.","triggerScenarios":"ParseDistinguishedName('CN=server,CN=alias.example.com') — a second CN (or O, OU, etc.) after a comma triggers markAttr. Note the first markAttr error (for the initial attribute) is deliberately discarded (_ = markAttr(prevAttr)), so only repeats from the second RDN onward surface.","commonSituations":"Templates or configs that concatenate subject components and emit 'O=Org1,O=Org2' instead of using a single multi-valued RDN 'O=Org1+O=Org2' or an OU list; users expecting RFC 4514 behavior where repeated attributes are legal.","solutions":["Remove the duplicate attributeType from the DN string","Merge values into one attribute where the parser supports lists (e.g. OU=a,OU=b fails too — combine into one value or a multi-valued RDN of the same type)","Move the second value into a different supported attribute (e.g. use OU for additional organization units)","Pre-validate the DN for duplicate keys before passing it to ParseDistinguishedName"],"exampleFix":"// before\nParseDistinguishedName(\"CN=proxy,CN=proxy-alt\")\n// after\nParseDistinguishedName(\"CN=proxy\")","handlingStrategy":"validation","validationCode":"func noDuplicateAttrs(dn string) error {\n\tseen := map[string]bool{}\n\tfor _, part := range strings.Split(dn, \",\") {\n\t\tkv := strings.SplitN(strings.TrimSpace(part), \"=\", 2)\n\t\tif len(kv) == 2 {\n\t\t\tif seen[kv[0]] { return fmt.Errorf(\"duplicate attribute %q in DN\", kv[0]) }\n\t\t\tseen[kv[0]] = true\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := noDuplicateAttrs(dn); err != nil { return err }\nname, err := pkixname.ParseDistinguishedName(dn)\nif err != nil { return fmt.Errorf(\"invalid DN %q: %w\", dn, err) }","preventionTips":["Never repeat an attribute type across comma-separated components","For repeated org units, decide on a single value or restructure with OU instead of multiple O's","Generate DNs from a fixed template instead of concatenating user input"],"tags":["x509","distinguished-name","parsing","validation"],"backgroundTag":"duplicate-attribute-dn","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}