iOfficeAI/OfficeCLI · error · CliException
invalid_value
invalid_value
Error message
{fieldName}: contains character invalid in XML 1.0 text ({problem}). Allowed: U+0009 (tab), U+000A (newline), U+000D (carriage return), and U+0020 and above (excluding surrogate code points and U+FFFE/U+FFFF). What it means
Thrown by XmlTextValidator.ValidateOrThrow when user-supplied text contains a character that is illegal in XML 1.0 character data. Open XML files (.docx/.xlsx/.pptx) are serialized as XML 1.0, so codepoints outside the allowed set (U+0009, U+000A, U+000D, U+0020–U+D7FF, U+E000–U+FFFD, U+10000–U+10FFFF via surrogate pairs) would cause XmlException at save time — which would leak as an internal_error and poison the in-memory document. This validator runs at every Add/Set entry point that accepts free-form text, catching the problem early with a deterministic, user-fixable CliException (code=invalid_value).
Source
Thrown at src/officecli/Core/XmlTextValidator.cs:83
return null;
}
/// <summary>
/// Throws <see cref="CliException"/> with code `invalid_value` when
/// <paramref name="text"/> contains a character forbidden in XML 1.0
/// character data. <paramref name="fieldName"/> appears in the error
/// message to help callers identify which input was rejected.
/// </summary>
public static void ValidateOrThrow(string? text, string fieldName, bool allowSoftBreakChar = false)
{
// NEWLINE-SEMANTICS-V2: '\v' (U+000B) is XML-illegal, but text
// pipelines that split it into <a:br/> / <w:br/> ELEMENTS before
// serialization (AppendLineWithTabs / AppendTextWithBreaks) may
// opt in — the char never reaches XML character data there.
var probe = allowSoftBreakChar ? text?.Replace("\v", "") : text;
var problem = FindInvalidChar(probe);
if (problem is null) return;
throw new CliException(
$"{fieldName}: contains character invalid in XML 1.0 text ({problem}). " +
"Allowed: U+0009 (tab), U+000A (newline), U+000D (carriage return), and U+0020 and above " +
"(excluding surrogate code points and U+FFFE/U+FFFF).")
{
Code = "invalid_value",
};
}
private static string FormatOffender(int cp, int offset)
=> $"U+{cp.ToString("X4", CultureInfo.InvariantCulture)} at offset {offset}";
}
View on GitHub (pinned to 1ced45e900)
Solutions
- Sanitize the input string before passing it to the API: strip or replace characters outside the XML 1.0 range.
- If the character is a vertical tab (U+000B) intended as a soft line break, check whether the calling pipeline supports allowSoftBreakChar=true (used by AppendLineWithTabs / AppendTextWithBreaks which split it into <w:br/> elements).
- Replace NUL bytes with nothing or a space: text.Replace("\0", "") before the call.
- If the text comes from an external source (HTTP, DB, LLM), add a sanitization filter at the ingestion boundary.
Example fix
// before: raw text from an external source may contain control chars
handler.Add("/paragraph", new { text = userInput });
// after: sanitize before the call
var clean = new StringBuilder();
foreach (var c in userInput)
if (c == '\t' || c == '\n' || c == '\r' || c >= 0x20)
clean.Append(c);
handler.Add("/paragraph", new { text = clean.ToString() }); Defensive patterns
Strategy: validation
Validate before calling
// Sanitize text before passing to any Add/Set API
static string SanitizeForXml(string? text)
{
if (string.IsNullOrEmpty(text)) return text ?? "";
var sb = new StringBuilder(text.Length);
foreach (var c in text)
{
if (c == '\t' || c == '\n' || c == '\r' || (c >= 0x20 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD))
sb.Append(c);
}
return sb.ToString();
} Type guard
// Type guard: returns null if text is XML-1.0-safe, otherwise the first offender
static string? XmlCharProblem(string? text)
=> OfficeCli.Core.XmlTextValidator.FindInvalidChar(text); Try / catch
try
{
handler.Add("/paragraph", new { text = userInput });
}
catch (CliException ex) when (ex.Code == "invalid_value" && ex.Message.Contains("invalid in XML 1.0"))
{
// Input contained illegal control characters — sanitize and retry
var sanitized = SanitizeForXml(userInput);
handler.Add("/paragraph", new { text = sanitized });
} Prevention
- Sanitize all external text (HTTP, DB, LLM, clipboard) at the ingestion boundary before it reaches document APIs.
- Strip NUL bytes explicitly: text.Replace("\0", "") — JavaScript/Node commonly allow NUL in strings.
- Use XmlTextValidator.FindInvalidChar as a pre-check when you need to know if text is safe without throwing.
- For vertical-tab soft breaks, pass allowSoftBreakChar=true only in pipelines that convert \v to <br/> elements before serialization.
When it happens
Trigger: Passing a string containing control characters such as NUL (U+0000), BEL (U+0007), vertical tab (U+000B, unless allowSoftBreakChar=true), form feed (U+000C), or unpaired surrogate code units. The offending codepoint and its byte offset are reported. Common when text originates from a database column, a clipboard paste, or an LLM-generated value that includes a stray control character.
Common situations: Copying text from a terminal or binary file that includes ANSI control codes; an API consumer sending a JSON string with embedded \u0000 (common from JavaScript/Node which allows NUL in strings); an LLM model emitting a U+000B vertical tab as a 'soft line break' (the allowSoftBreakChar opt-in exists specifically for this pipeline); a copy-paste from a PDF that includes form-feed or other formatting control characters.
Related errors
- invalid_value
- invalid_render
- invalid_value
- invalid_value
- Invalid --prop '{prop}': key is empty. Use key=value (e.g. -
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/5e996fe813692d3e.
Report an issue: GitHub.