iOfficeAI/OfficeCLI · error · ArgumentException
{propName} contains an unpaired high surrogate U+{(int)c:X4}
Error message
{propName} contains an unpaired high surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair. What it means
Thrown by ValidateXmlText when a high surrogate (U+D800–U+DBFF) is not followed by a low surrogate. XML 1.0 character data forbids lone UTF-16 surrogate halves; only a complete high+low pair encodes a valid supplementary-plane code point. The validator advances past a matched pair, so this fires only for an unmatched high surrogate.
Source
Thrown at src/officecli/Core/ParseHelpers.cs:860
if (c == '\t' || c == '\n' || c == '\r') continue;
// '\v' (0x0B) is XML-illegal as character data. It is allowed ONLY
// when the caller consumes it into a break ELEMENT before
// serialization (NEWLINE-SEMANTICS-V2: AppendTextWithBreaks turns
// '\v' into <w:br/>). Callers that write validated text verbatim
// into XML (chart titles, xlsx cell values, headers, ...) keep the
// strict default so '\v' can never reach raw character data.
if (c == '\v' && allowSoftBreakChar) continue;
if (c < 0x20)
throw new ArgumentException(
$"{propName} contains XML-illegal control character U+{(int)c:X4} at position {i}. " +
"Allowed control chars: \\t, \\n, \\r" +
(allowSoftBreakChar ? ", \\v." : "."));
// UTF-16 surrogates only valid in pairs (high then low). A lone
// half is illegal in XML 1.0 character data.
if (char.IsHighSurrogate(c))
{
if (i + 1 >= value.Length || !char.IsLowSurrogate(value[i + 1]))
throw new ArgumentException(
$"{propName} contains an unpaired high surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair.");
i++; // skip the matched low surrogate
continue;
}
if (char.IsLowSurrogate(c))
throw new ArgumentException(
$"{propName} contains an unpaired low surrogate U+{(int)c:X4} at position {i}. Use a complete UTF-16 surrogate pair.");
if (c == 0xFFFE || c == 0xFFFF)
throw new ArgumentException(
$"{propName} contains the XML-illegal noncharacter U+{(int)c:X4} at position {i}.");
}
}
}
View on GitHub (pinned to 1ced45e900)
Solutions
- Avoid splitting strings at arbitrary indices when they may contain supplementary-plane characters; use text-element or grapheme-aware boundaries (StringInfo).
- Ensure the source bytes are fully and correctly decoded to UTF-16 before setting the value.
- If truncation is needed, use StringInfo.SubstringByTextElements to avoid breaking surrogate pairs.
Example fix
// before var s = "\uD83D"; // lone high surrogate (smiley missing its low half) // after var s = "\uD83D\uDE00"; // complete surrogate pair
Defensive patterns
Strategy: validation
Validate before calling
// Reject strings containing a lone high surrogate (no following low surrogate):
static bool HasNoLoneSurrogates(string s)
{
for (int i = 0; i < s.Length; i++)
{
if (char.IsHighSurrogate(s, i) && (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1]))) return false;
if (char.IsLowSurrogate(s, i) && (i == 0 || !char.IsHighSurrogate(s[i - 1]))) return false;
}
return true;
} Prevention
- Use StringInfo for substring/truncate operations on text that may contain emoji.
- Fully decode source bytes to UTF-16 before setting.
- Avoid slicing strings at arbitrary indices across surrogate pairs.
When it happens
Trigger: Thrown at src/officecli/Core/ParseHelpers.cs:860 when the library encounters an invalid state.
Common situations: Truncating user text at a fixed character count that lands between a surrogate pair; .Substring on a string containing emoji/supplementary-plane chars; decoding a byte stream as UTF-16 with a truncated final character.
Related errors
- {propName} contains an unpaired low surrogate U+{(int)c:X4}
- {propName} contains the XML-illegal noncharacter U+{(int)c:X
- {propName} contains XML-illegal control character U+{(int)c:
- Invalid '{propertyName}' value '{value}': degrees must be in
- Invalid color value: '{value}'. Expected 6-digit hex RGB (e.
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/f196de170e0b5a79.
Report an issue: GitHub.