{"record":{"id":"aeaf33b59d98a02c","repo":"XINCGer/Unity3DTraining","slug":"string-contains-high-surrogate-not-preceded-by-low","errorCode":null,"errorMessage":"String contains high surrogate not preceded by low surrogate","messagePattern":"String contains high surrogate not preceded by low surrogate","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonFormatter.cs","lineNumber":710,"sourceCode":"                    writer.Write(CommonRepresentations[c]);\n                    continue;\n                }\n                if (char.IsHighSurrogate(c))\n                {\n                    // Encountered first part of a surrogate pair.\n                    // Check that we have the whole pair, and encode both parts as hex.\n                    i++;\n                    if (i == text.Length || !char.IsLowSurrogate(text[i]))\n                    {\n                        throw new ArgumentException(\"String contains low surrogate not followed by high surrogate\");\n                    }\n                    HexEncodeUtf16CodeUnit(writer, c);\n                    HexEncodeUtf16CodeUnit(writer, text[i]);\n                    continue;\n                }\n                else if (char.IsLowSurrogate(c))\n                {\n                    throw new ArgumentException(\"String contains high surrogate not preceded by low surrogate\");\n                }\n                switch ((uint)c)\n                {\n                    // These are not required by json spec\n                    // but used to prevent security bugs in javascript.\n                    case 0xfeff:  // Zero width no-break space\n                    case 0xfff9:  // Interlinear annotation anchor\n                    case 0xfffa:  // Interlinear annotation separator\n                    case 0xfffb:  // Interlinear annotation terminator\n\n                    case 0x00ad:  // Soft-hyphen\n                    case 0x06dd:  // Arabic end of ayah\n                    case 0x070f:  // Syriac abbreviation mark\n                    case 0x17b4:  // Khmer vowel inherent Aq\n                    case 0x17b5:  // Khmer vowel inherent Aa\n                        HexEncodeUtf16CodeUnit(writer, c);\n                        break;\n","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/JsonFormatter.cs#L692-L728","documentation":"JsonFormatter's WriteString found a low surrogate (second half of a UTF-16 surrogate pair) without a preceding high surrogate. A lone low surrogate is not a valid Unicode character, so the formatter refuses to emit it into JSON and throws ArgumentException.","triggerScenarios":"Formatting a message whose string field starts with or contains a lone low surrogate (U+DC00–U+DFFF) not preceded by a high surrogate — caused by malformed decoded data, byte truncation, or manual string construction from raw char arrays.","commonSituations":"Decoding binary/network payloads with incorrect encodings; concatenating or slicing strings at odd offsets; receiving corrupted data from external systems; storing arbitrary bytes in string fields.","solutions":["Validate string fields contain well-formed UTF-16 before assigning them to the message","Re-decode the source bytes with the correct encoding (usually UTF-8) instead of treating raw bytes as UTF-16","Sanitize/strip invalid surrogate chars before formatting","Catch ArgumentException at the serialization boundary and quarantine the bad record"],"exampleFix":"// before\nmsg.Name = new string(chars, offset, len); // offset may start on a low surrogate\n// after\nstatic bool WellFormed(string s) { for (int i = 0; i < s.Length; i++) if (char.IsSurrogate(s[i]) && (i + 1 >= s.Length || !char.IsSurrogatePair(s[i], s[i+1]))) return false; return true; }\nif (WellFormed(text)) msg.Name = text;","handlingStrategy":"validation","validationCode":"static bool IsWellFormedUtf16(string s) { for (int i = 0; i < s.Length; i++) { if (char.IsHighSurrogate(s[i])) { if (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1])) return false; i++; } else if (char.IsLowSurrogate(s[i])) return false; } return true; }","typeGuard":"static bool HasLoneLowSurrogate(string s) { for (int i = 0; i < s.Length; i++) if (char.IsLowSurrogate(s[i]) && (i == 0 || !char.IsHighSurrogate(s[i - 1]))) return true; return false; }","tryCatchPattern":"try { return formatter.Format(message); } catch (ArgumentException ex) when (ex.Message.Contains(\"high surrogate\")) { log.Warn(\"Lone low surrogate in string field\"); return null; }","preventionTips":["Sanitize strings from untrusted sources before assigning to proto fields","Avoid manual char-buffer slicing of strings","Round-trip check via Encoding.UTF8 with exception throwing to catch invalid data early"],"tags":["protobuf","json-serialization","utf-16","surrogate-pair","string-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"016f98412ea5e11756b286736f479b66ab6216d5","analyzedAt":"2026-09-12T01:08:58.711Z","contentChangedAt":"2026-09-12T01:08:58.711Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}