{"record":{"id":"68df971df505ff10","repo":"gravitational/teleport","slug":"want-attributetype-found-q-s","errorCode":null,"errorMessage":"want attributeType, found %q: %s","messagePattern":"want attributeType, found %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":491,"sourceCode":"\t\t\t\temitBuffer(tokenString)\n\t\t\t\ttransitionToNameComponent(r)\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\ttrailingSpaceBuf.WriteTo(buf) // whitespace copied back.\n\t\t\t\ttrailingSpaceBuf.Reset()\n\t\t\t\tstate = tokenizeStateString\n\t\t\t\t// Rune not consumed.\n\t\t\t}\n\t\t}\n\n\t\tswitch state {\n\t\tcase tokenizeStateInit, tokenizeStateNameComponent:\n\t\t\tswitch {\n\t\t\tcase isAttrType(r):\n\t\t\t\tstate = tokenizeStateAttrType\n\t\t\t\tbuf.WriteRune(r)\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"want attributeType, found %q: %s\", r, errTrace(pos))\n\t\t\t}\n\n\t\tcase tokenizeStateAttrType:\n\t\t\tswitch {\n\t\t\tcase isAttrType(r):\n\t\t\t\tbuf.WriteRune(r)\n\t\t\tcase r == '=':\n\t\t\t\temitBuffer(tokenAttrType)\n\t\t\t\temit(tokenEqual)\n\t\t\t\tstate = tokenizeStateStringStart\n\t\t\tcase r == ' ':\n\t\t\t\temitBuffer(tokenAttrType)\n\t\t\t\tstate = tokenizeStateAttrTypeEnd\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"want attributeType or '=', found %q: %s\", r, errTrace(pos))\n\t\t\t}\n\n\t\tcase tokenizeStateAttrTypeEnd:","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L473-L509","documentation":"The DN tokenizer expects every RDN to start with an attribute type (letters, digits, '-', '.'). In the Init or NameComponent state, if the first character after a separator (or at the start of the DN) is not a valid attribute-type character, tokenization fails with this error, which includes the offending rune and the position/substring.","triggerScenarios":"Calling ParseDistinguishedName with a DN that starts with or follows a ','/';'/'+' with a non-attribute-type character, e.g. \"=Bob\", \"CN=foo,,CN=bar\", \"CN=foo, =bar\", or a value starting with an unescaped special character like \"+CN=a\".","commonSituations":"Empty RDN components from doubled commas, DNs with leading/trailing separators, copy-pasted DNs with stray punctuation, or values meant to be quoted/escaped that were not (e.g. \"O=<Corp>\").","solutions":["Remove empty components or stray separators from the DN string.","Escape special characters in values with '\\\\', e.g. \"O=\\\\+Corp\", or quote the value: \"O=\\\"+Corp\\\"\".","Ensure each comma/plus-separated segment begins with an attribute type like CN=, O=, OU=.","Pre-validate the DN with a regex requiring each RDN to match [A-Za-z0-9.-]+="],"exampleFix":"// before\nname, err := pkixname.ParseDistinguishedName(\"CN=foo,,O=bar\")\n// after\nname, err := pkixname.ParseDistinguishedName(\"CN=foo,O=bar\")","handlingStrategy":"validation","validationCode":"var rdnStartRe = regexp.MustCompile(`^[A-Za-z0-9.-]+\\s*=`)\nfunc validRDNStarts(dn string) bool {\n\tfor _, part := range strings.Split(dn, \",\") {\n\t\tif strings.TrimSpace(part) == \"\" || !rdnStartRe.MatchString(strings.TrimSpace(part)) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":"name, err := pkixname.ParseDistinguishedName(dn)\nif err != nil {\n\treturn nil, fmt.Errorf(\"invalid distinguished name %q: %w\", dn, err)\n}","preventionTips":["Validate DN strings at config load time, not just at use time","Strip empty components before joining with ','","Escape or quote special characters in values"],"tags":["x509","distinguished-name","parser","syntax"],"backgroundTag":"dn-malformed-syntax","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}