{"record":{"id":"6c243156d75b8154","repo":"gravitational/teleport","slug":"want-attributetype-found-eof","errorCode":null,"errorMessage":"want attributeType, found EOF","messagePattern":"want attributeType, found EOF","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":576,"sourceCode":"\t\t\t\tbuf.WriteRune(r)\n\t\t\t}\n\n\t\tcase tokenizeStateStringQuoteEnd:\n\t\t\tswitch r {\n\t\t\tcase '+', ',', ';':\n\t\t\t\ttransitionToNameComponent(r)\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"want '+' or ',', found %q: %s\", r, errTrace(pos))\n\t\t\t}\n\t\t}\n\t}\n\n\t// Input ended, check the final state.\n\tswitch state {\n\tcase tokenizeStateInit:\n\t\t// OK.\n\tcase tokenizeStateNameComponent:\n\t\treturn nil, fmt.Errorf(\"want attributeType, found EOF\")\n\tcase tokenizeStateAttrType:\n\t\treturn nil, fmt.Errorf(\"want attributeType or '=', found EOF\")\n\tcase tokenizeStateAttrTypeEnd:\n\t\treturn nil, fmt.Errorf(\"want '=' attributeValue, found EOF\")\n\tcase tokenizeStateStringStart, tokenizeStateString, tokenizeStateStringEnd:\n\t\t// OK.\n\t\temitBuffer(tokenString)\n\tcase tokenizeStateStringEscape:\n\t\treturn nil, fmt.Errorf(\"want escaped character, found EOF\")\n\tcase tokenizeStateStringQuote:\n\t\treturn nil, fmt.Errorf(\"want closing quote, found EOF\")\n\tcase tokenizeStateStringQuoteEnd:\n\t\t// OK.\n\tdefault:\n\t\t// This should not be reached. All states are handled above.\n\t\treturn nil, fmt.Errorf(\"found EOF (state=%d)\", state)\n\t}\n","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L558-L594","documentation":"The DN string ended while the tokenizer was expecting the start of a new attribute type — i.e. the input ended right after a ',' or '+' separator with no following RDN. Trailing separators are invalid; every separator must be followed by another type=value pair.","triggerScenarios":"Calling ParseDistinguishedName with a DN ending in ',' or '+', e.g. \"CN=Bob,\", \"O=Corp,CN=Bob+\", or input truncated after a separator.","commonSituations":"DNs built by joining components with strings.Join over a slice with an empty trailing element, config lines truncated, or copy-paste that dropped the last component.","solutions":["Remove the trailing ',' or '+' from the DN string.","Filter out empty components before building the DN (skip empty attribute slices when joining).","Pre-validate that the DN does not end with a separator before parsing."],"exampleFix":"// before\nname, err := pkixname.ParseDistinguishedName(\"CN=Bob,O=Corp,\")\n// after\nname, err := pkixname.ParseDistinguishedName(\"CN=Bob,O=Corp\")","handlingStrategy":"validation","validationCode":"func trailingSeparator(dn string) bool {\n\tdn = strings.TrimRight(dn, \" \")\n\treturn strings.HasSuffix(dn, \",\") || strings.HasSuffix(dn, \"+\") || strings.HasSuffix(dn, \";\")\n}","typeGuard":null,"tryCatchPattern":"name, err := pkixname.ParseDistinguishedName(dn)\nif err != nil {\n\tif strings.HasSuffix(dn, \",\") || strings.HasSuffix(dn, \"+\") {\n\t\treturn nil, fmt.Errorf(\"DN %q ends with a separator\", dn)\n\t}\n\treturn nil, err\n}","preventionTips":["Trim trailing separators before parsing","Skip empty attribute slices when building DN strings","Validate DNs at config-load time"],"tags":["x509","distinguished-name","parser","truncated-input"],"backgroundTag":"dn-trailing-separator","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}