{"record":{"id":"8a1ed15502bd9ea3","repo":"gravitational/teleport","slug":"want-escaped-character-found-eof","errorCode":null,"errorMessage":"want escaped character, found EOF","messagePattern":"want escaped character, found EOF","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":585,"sourceCode":"\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\n\treturn tokens, nil\n}\n\nfunc isAttrType(r rune) bool {\n\treturn r >= 'A' && r <= 'Z' ||\n\t\tr >= 'a' && r <= 'z' ||\n\t\tr >= '0' && r <= '9' ||\n\t\tr == '-' ||\n\t\tr == '.'","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L567-L603","documentation":"ParseDistinguishedName's tokenizer reached the end of the input while in tokenizeStateStringEscape, i.e. the DN string ended immediately after a backslash escape character. The parser requires a character after every '\\' because escaped runes are how special DN characters (',', '+', '=', etc.) are represented literally. It cannot emit a token, so it fails the whole parse.","triggerScenarios":"Calling ParseDistinguishedName (directly or via pkixname parsing APIs) with a DN whose value ends in a trailing backslash, e.g. \"CN=foo\\\\\" or \"OU=eng,O=corp\\\\\" — the escape sequence is never completed before EOF.","commonSituations":"DNs built by string concatenation or template rendering where a trailing separator/backslash is left behind; DNs copy-pasted from shell commands where the trailing backslash was a line continuation; truncated config values or environment variables holding partial DNs.","solutions":["Remove the trailing backslash or complete the escape sequence (e.g. \"CN=foo\\\\,\" instead of \"CN=foo\\\\\").","If the backslash is meant literally, double it: \"CN=foo\\\\\\\\\".","Trim/validate DN strings at the config-loading boundary before passing them to the parser."],"exampleFix":"// before\n_dn := \"CN=service,O=corp\\\\\"\nname, err := pkixname.ParseDistinguishedName(_dn)\n// after\n_dn := strings.TrimRight(rawDN, \"\\\\\") // or fix the escape: \"CN=service\\\\,O=corp\"\nname, err := pkixname.ParseDistinguishedName(_dn)","handlingStrategy":"validation","validationCode":"func validDNEscapes(dn string) bool {\n\tfor i := 0; i < len(dn); i++ {\n\t\tif dn[i] == '\\\\' && i == len(dn)-1 {\n\t\t\treturn false // trailing backslash, nothing to escape\n\t\t}\n\t\tif dn[i] == '\\\\' {\n\t\t\ti++ // skip escaped char\n\t\t}\n\t}\n\treturn true\n}\nif !validDNEscapes(rawDN) { return errors.New(\"DN ends with incomplete escape sequence\") }","typeGuard":null,"tryCatchPattern":"var name *pkixname.Name\nif err := ...; err != nil {\n\tif strings.Contains(err.Error(), \"want escaped character\") {\n\t\t// treat DN as corrupt input: reject or sanitize trailing backslash and retry\n\t}\n}","preventionTips":["Never build DNs by naive string concatenation; use a builder that escapes values.","Trim trailing separators/backslashes from DN strings at config load.","Unit-test DNs containing escaped characters (\\, \\+ \\= \\\\)."],"tags":["parsing","ldap","dn","eof"],"backgroundTag":"dn-string-unterminated-escape","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}