{"record":{"id":"6bb33a063de58ae8","repo":"antlr/antlr4","slug":"invalid-utf-16-low-surrogate-with-no-preceding-hi-6bb33a","errorCode":null,"errorMessage":"Invalid UTF-16 (low surrogate with no preceding high surrogate)","messagePattern":"Invalid UTF-16 \\(low surrogate with no preceding high surrogate\\)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/UnbufferedCharStream.cs","lineNumber":230,"sourceCode":"        {\n            for (int i = 0; i < n; i++)\n            {\n                if (this.n > 0 && data[this.n - 1] == IntStreamConstants.EOF)\n                {\n                    return i;\n                }\n\n                int c = NextChar();\n                if (c > char.MaxValue || c == IntStreamConstants.EOF)\n                {\n                    Add(c);\n                }\n                else\n                {\n                    char ch = unchecked((char)c);\n                    if (Char.IsLowSurrogate(ch))\n                    {\n                        throw new ArgumentException(\"Invalid UTF-16 (low surrogate with no preceding high surrogate)\");\n                    }\n                    else if (Char.IsHighSurrogate(ch))\n                    {\n                        int lowSurrogate = NextChar();\n                        if (lowSurrogate > char.MaxValue)\n                        {\n                            throw new ArgumentException(\"Invalid UTF-16 (high surrogate followed by code point > U+FFFF\");\n                        }\n                        else if (lowSurrogate == IntStreamConstants.EOF)\n                        {\n                            throw new ArgumentException(\"Invalid UTF-16 (low surrogate with no preceding high surrogate)\");\n                        }\n                        else\n                        {\n                            char lowSurrogateChar = unchecked((char)lowSurrogate);\n                            if (Char.IsLowSurrogate(lowSurrogateChar))\n                            {\n                                Add(Char.ConvertToUtf32(ch, lowSurrogateChar));","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/UnbufferedCharStream.cs#L212-L248","documentation":"While filling its buffer, UnbufferedCharStream decodes UTF-16 code units and validates surrogate pairs. This throw occurs when the next code unit is a low surrogate (U+DC00..U+DFFF) but no preceding high surrogate was seen, so it cannot form a valid Unicode scalar value.","triggerScenarios":"The underlying TextReader returns a string such as \"\\uDC00\" at the current position; a surrogate pair is split and only its low half reaches the stream; or malformed UTF-16 is decoded without error detection before ANTLR reads it.","commonSituations":"Corrupt source files; incorrect encoding conversion; slicing strings in the middle of surrogate pairs; network or database data containing unpaired surrogates; or custom TextReader implementations.","solutions":["Fix the input so every low surrogate is preceded by a matching high surrogate.","Validate or re-encode the source as well-formed UTF-8/UTF-16 before creating the stream.","Avoid substring operations that can split surrogate pairs.","Audit custom TextReader/ICharStream adapters for malformed code-unit sequencing."],"exampleFix":"// before\nvar bad = \"\\uDC00\";\nvar stream = new UnbufferedCharStream(new StringReader(bad));\n\n// after\nvar good = \"\\U0001F600\"; // complete surrogate pair\nvar stream = new UnbufferedCharStream(new StringReader(good));","handlingStrategy":"validation","validationCode":"static bool HasValidUtf16Pairs(string s) {\n    for (int i = 0; i < s.Length; i++) {\n        if (char.IsLowSurrogate(s[i]) && (i == 0 || !char.IsHighSurrogate(s[i-1]))) return false;\n        if (char.IsHighSurrogate(s[i]) && (i + 1 >= s.Length || !char.IsLowSurrogate(s[i+1]))) return false;\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { var stream = new UnbufferedCharStream(new StringReader(text)); stream.Fill(1); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Invalid UTF-16\")) { /* reject malformed input */ }","preventionTips":["Use UTF8/Unicode decoders that throw on invalid sequences.","Never split strings between surrogate halves.","Validate externally sourced text before parsing."],"tags":["antlr","csharp","unicode","utf-16","input-validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}