{"record":{"id":"a18285db9c5536c9","repo":"nats-io/nats-server","slug":"failed-to-decode-escaped-character-s","errorCode":null,"errorMessage":"failed to decode escaped character: %s","messagePattern":"failed to decode escaped character: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ldap/dn.go","lineNumber":163,"sourceCode":"\t\tchar := str[i]\n\t\tswitch {\n\t\tcase escaping:\n\t\t\tunescapedTrailingSpaces = 0\n\t\t\tescaping = false\n\t\t\tswitch char {\n\t\t\tcase ' ', '\"', '#', '+', ',', ';', '<', '=', '>', '\\\\':\n\t\t\t\tbuffer.WriteByte(char)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Not a special character, assume hex encoded octet\n\t\t\tif len(str) == i+1 {\n\t\t\t\treturn nil, errors.New(\"got corrupted escaped character\")\n\t\t\t}\n\n\t\t\tdst := []byte{0}\n\t\t\tn, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to decode escaped character: %s\", err)\n\t\t\t} else if n != 1 {\n\t\t\t\treturn nil, fmt.Errorf(\"expected 1 byte when un-escaping, got %d\", n)\n\t\t\t}\n\t\t\tbuffer.WriteByte(dst[0])\n\t\t\ti++\n\t\tcase char == '\\\\':\n\t\t\tunescapedTrailingSpaces = 0\n\t\t\tescaping = true\n\t\tcase char == '=':\n\t\t\tattribute.Type = stringFromBuffer()\n\t\t\t// Special case: If the first character in the value is # the following data\n\t\t\t// is BER encoded. Throw an error since not supported right now.\n\t\t\tif len(str) > i+1 && str[i+1] == '#' {\n\t\t\t\treturn nil, errors.New(\"unsupported BER encoding\")\n\t\t\t}\n\t\tcase char == ',' || char == '+':\n\t\t\t// We're done with this RDN or value, push it\n\t\t\tif len(attribute.Type) == 0 {","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/internal/ldap/dn.go#L145-L181","documentation":"ParseDN parses an LDAP distinguished-name string. When it encounters a hex-escaped character (\\XX), it decodes the two hex digits with encoding/hex; if the pair is not valid hex, it returns this error wrapping the decode failure.","triggerScenarios":"Calling ParseDN with a DN containing a backslash escape followed by fewer than 2 valid hex characters, e.g. \"CN=\\G1\" or \"CN=\\4\".","commonSituations":"Hand-edited bind DNs or config files with improperly escaped special characters; DNs copied from tools that use different escaping conventions (e.g. \\, instead of \\2C).","solutions":["Fix the DN string so every backslash escape is exactly two hex digits (e.g. \\2C for comma)","Check the source of the DN for double-escaping (e.g. \\\\2C read from config)","Validate the DN with a regex/validator before passing it to ParseDN"],"exampleFix":"// before\ndn, err := ParseDN(\"CN=\\G1,OU=Engineering\")\n// after\ndn, err := ParseDN(\"CN=\\47 1,OU=Engineering\") // or \"CN=G1,OU=Engineering\"","handlingStrategy":"validation","validationCode":"var dnEscapeRe = regexp.MustCompile(`\\\\[0-9a-fA-F]{2}`)\n// every '\\' in a DN must be followed by two hex digits\nif strings.Contains(dn, \"\\\\\") && !validEscapes(dn, dnEscapeRe) {\n    return fmt.Errorf(\"DN %q has malformed hex escape\", dn)\n}","typeGuard":null,"tryCatchPattern":"dn, err := ParseDN(input)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to decode escaped character\") {\n        return fmt.Errorf(\"bad DN input %q: %w\", input, err)\n    }\n    return err\n}","preventionTips":["Escape DN special chars as hex pairs (\\2C not \\,)","Avoid hand-editing DNs; generate them programmatically","Validate config DNs at startup"],"tags":["ldap","dn-parsing","hex-decoding"],"backgroundTag":"invalid-ldap-dn-escape","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}