{"record":{"id":"4b5dc47c266f8259","repo":"nats-io/nats-server","slug":"expected-1-byte-when-un-escaping-got-d","errorCode":null,"errorMessage":"expected 1 byte when un-escaping, got %d","messagePattern":"expected 1 byte when un-escaping, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ldap/dn.go","lineNumber":165,"sourceCode":"\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 {\n\t\t\t\treturn nil, errors.New(\"incomplete type, value pair\")\n\t\t\t}","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/internal/ldap/dn.go#L147-L183","documentation":"ParseDN decodes hex escapes into a single-byte buffer. If encoding/hex.Decode reports it consumed/produced a count other than 1 byte, the escape was not a valid single-byte pair, and this error is returned.","triggerScenarios":"Calling ParseDN with a DN whose escape sequence decodes to something other than one byte — practically triggered by malformed input that slips past basic validation, or by a sliced escape substring shorter than 2 bytes at the end of the string.","commonSituations":"Truncated escape at end of DN string (\"CN=A\\4\"), corrupted DN data read from files or network, off-by-one in DN-manipulation code that slices the string before parsing.","solutions":["Ensure each backslash escape is followed by exactly two hex characters and the DN is not truncated","Trim/repair the DN source (file, env var, config) of stray whitespace or truncation","Pre-validate DN length/escaping before calling ParseDN"],"exampleFix":"// before\ndn, err := ParseDN(\"CN=Server\\4\")\n// after\ndn, err := ParseDN(\"CN=Server\\40\")","handlingStrategy":"validation","validationCode":"if len(dn) >= 1 && strings.HasSuffix(dn, \"\\\\\") {\n    return fmt.Errorf(\"DN %q ends with dangling escape\", dn)\n}\nif !dnEscapeSequenceRegex.MatchString(dn) {\n    return fmt.Errorf(\"DN %q has invalid escape sequence\", dn)\n}","typeGuard":null,"tryCatchPattern":"dn, err := ParseDN(input)\nif err != nil {\n    if strings.Contains(err.Error(), \"expected 1 byte when un-escaping\") {\n        return fmt.Errorf(\"truncated escape in DN %q: %w\", input, err)\n    }\n    return err\n}","preventionTips":["Never truncate DN strings (check file/env reads for corruption)","Ensure all escapes are full two-char hex pairs","Round-trip test: ParseDN DN, render back, compare"],"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-08T15:18:49.778Z"}