{"record":{"id":"7c9cd712c96a2cee","repo":"iOfficeAI/OfficeCLI","slug":"propname-contains-an-unpaired-low-surrogate-u","errorCode":null,"errorMessage":"{propName} contains an unpaired low surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair.","messagePattern":"(.+?) contains an unpaired low surrogate U\\+(.+?) at position (.+?)\\. Use a complete UTF-16 surrogate pair\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/ParseHelpers.cs","lineNumber":866,"sourceCode":"            // strict default so '\\v' can never reach raw character data.\n            if (c == '\\v' && allowSoftBreakChar) continue;\n            if (c < 0x20)\n                throw new ArgumentException(\n                    $\"{propName} contains XML-illegal control character U+{(int)c:X4} at position {i}. \" +\n                    \"Allowed control chars: \\\\t, \\\\n, \\\\r\" +\n                    (allowSoftBreakChar ? \", \\\\v.\" : \".\"));\n            // UTF-16 surrogates only valid in pairs (high then low). A lone\n            // half is illegal in XML 1.0 character data.\n            if (char.IsHighSurrogate(c))\n            {\n                if (i + 1 >= value.Length || !char.IsLowSurrogate(value[i + 1]))\n                    throw new ArgumentException(\n                        $\"{propName} contains an unpaired high surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair.\");\n                i++; // skip the matched low surrogate\n                continue;\n            }\n            if (char.IsLowSurrogate(c))\n                throw new ArgumentException(\n                    $\"{propName} contains an unpaired low surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair.\");\n            if (c == 0xFFFE || c == 0xFFFF)\n                throw new ArgumentException(\n                    $\"{propName} contains the XML-illegal noncharacter U+{(int)c:X4} at position {i}.\");\n        }\n    }\n}\n","sourceCodeStart":848,"sourceCodeEnd":874,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/ParseHelpers.cs#L848-L874","documentation":"Thrown by ValidateXmlText when a low surrogate (U+DC00–U+DFFF) appears without a preceding high surrogate. Low surrogates are only valid as the second half of a pair; a lone low surrogate is illegal in XML 1.0 character data.","triggerScenarios":"A string that starts with or contains an isolated low surrogate, e.g. from slicing a pair and keeping the trailing half, or from manually constructing chars from raw code units where the high half was dropped.","commonSituations":"String slicing/removal that deleted the high half of an emoji but kept the low half; decoding errors; constructing strings from unvalidated char arrays.","solutions":["Reconstruct or re-encode the original text so every low surrogate is preceded by its matching high surrogate.","Use text-element-aware APIs (StringInfo) for substring/remove operations on text that may contain supplementary-plane characters.","Filter out lone surrogates before setting the value if you cannot recover the pair."],"exampleFix":"// before\nvar s = \"\\uDE00\";            // lone low surrogate\n// after\nvar s = \"\\uD83D\\uDE00\";      // complete pair","handlingStrategy":"validation","validationCode":"static bool HasNoLoneSurrogates(string s)\n{\n    for (int i = 0; i < s.Length; i++)\n    {\n        if (char.IsHighSurrogate(s, i) && (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1]))) return false;\n        if (char.IsLowSurrogate(s, i) && (i == 0 || !char.IsHighSurrogate(s[i - 1]))) return false;\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep surrogate pairs intact during text manipulation.","Use text-element-aware APIs for remove/substring.","Strip lone surrogates from untrusted input before setting."],"tags":["xml","input-validation","unicode","surrogate","ooxml","officecli"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}