iOfficeAI/OfficeCLI · error · CliException

invalid_input

invalid_input

Error message

path contains a NUL byte (\u0000), which is invalid in OOXML.

What it means

Thrown by ExecuteBatchItem at the batch boundary when item.Path contains a U+0000 (NUL) byte. OOXML XML writers throw a System.Xml.XmlException on NUL deep inside the SDK Save path, AFTER earlier batch items have already mutated the document, which would lose every subsequent mutation in the session. Rejecting up front records exactly one failed step and keeps the rest of the document intact. CliException Code="invalid_input".

Source

Thrown at src/officecli/CommandBuilder.cs:916

    }

    internal static string ExecuteBatchItem(OfficeCli.Core.IDocumentHandler handler, BatchItem item, bool json)
    {
        var format = json ? OfficeCli.Core.OutputFormat.Json : OfficeCli.Core.OutputFormat.Text;
        var props = item.Props ?? new Dictionary<string, string>();

        // Reject null bytes (U+0000) anywhere in caller-controlled strings —
        // path, selector, text, and prop values. OOXML xml writers throw
        // System.Xml.XmlException ("'.', hexadecimal value 0x00, is an
        // invalid character.") deep inside the SDK's Save path, AFTER prior
        // batch items have already mutated the document. The exception
        // bubbles up past the handler's Save and leaves the resident in a
        // state where the next close throws again — silently losing every
        // successful mutation in the same session. Reject at the boundary
        // with a stable code so the batch driver records ONE failed step
        // and keeps the rest of the document intact.
        if (ContainsNullByte(item.Path))
            throw new CliException($"path contains a NUL byte (\\u0000), which is invalid in OOXML.")
                { Code = "invalid_input" };
        if (ContainsNullByte(item.Selector))
            throw new CliException($"selector contains a NUL byte (\\u0000), which is invalid in OOXML.")
                { Code = "invalid_input" };
        if (ContainsNullByte(item.Text))
            throw new CliException($"text contains a NUL byte (\\u0000), which is invalid in OOXML.")
                { Code = "invalid_input" };
        foreach (var (pk, pv) in props)
        {
            if (ContainsNullByte(pk) || ContainsNullByte(pv))
                throw new CliException($"prop '{pk}' contains a NUL byte (\\u0000), which is invalid in OOXML.")
                    { Code = "invalid_input" };
        }

        switch (item.Command.ToLowerInvariant())
        {
            // NEWLINE-SEMANTICS-V2: version-stamp items are normally stripped
            // by BatchCompat.PrepareForReplay; tolerate one that reaches the

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Sanitize every caller-controlled string: strip or replace NUL bytes before building the batch item.
  2. Validate source data encoding (treat NUL as a fatal input error at ingest).
  3. For path values, replace '\u0000' with an empty string or reject the whole payload.
  4. Add a pre-submission assertion that no field contains '\u0000'.

Example fix

// before
{"command":"set","path":"/\u0000slide[1]","props":{"bold":"true"}}
// after
{"command":"set","path":"/slide[1]","props":{"bold":"true"}}
Defensive patterns

Strategy: validation

Validate before calling

static string Sanitize(string? s) => (s ?? "").Replace("\u0000", "");
item.Path = Sanitize(item.Path);
if (item.Path.Contains('\u0000')) throw new ArgumentException("path has NUL");

Prevention

When it happens

Trigger: {"command":"set","path":"/\u0000slide[1]","props":{"bold":"true"}}; a path string assembled from a C-style NUL-terminated buffer; binary/external data sourcing that injects control characters.

Common situations: Pasting data sourced from binary protocols or legacy systems; an upstream bug that embeds NUL terminators; NDJSON plugin emitting raw bytes; templating that interpolated an uninitialized/null-terminated string field.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/781bdde888a323a3. Report an issue: GitHub.