iOfficeAI/OfficeCLI · error · ArgumentException

comment runs: invalid JSON array

Error message

comment runs: invalid JSON array — {ex.Message}

What it means

Thrown by BuildCommentTextFromRuns when JsonNode.Parse raises a JsonException on the `runs=<json>` value for a comment. The runs value must be a parseable JSON string; any malformed JSON (missing quotes, trailing comma, unescaped char) bubbles up wrapped as an ArgumentException with the parser's message.

Solutions

  1. Validate the runs string parses as JSON before sending it (JsonNode.Parse or json.loads in the caller).
  2. Build the runs array with a JSON serializer (System.Text.Json.JsonSerializer.Serialize or json.dumps), never string concatenation.
  3. Check the parser message in the exception text — it pinpoints the byte offset of the syntax error.

Example fix

// before
string runs = "[{\"text\":\"hi\"},]"; // trailing comma
BuildCommentTextFromRuns(runs);
// after
var runsObj = new[] { new { text = "hi" } };
string runs = System.Text.Json.JsonSerializer.Serialize(runsObj);
BuildCommentTextFromRuns(runs);
Defensive patterns

Strategy: validation

Validate before calling

// Validate before the API call
static bool IsValidRunsJson(string runsJson)
{
    try { using var doc = System.Text.Json.JsonDocument.Parse(runsJson); return doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array; }
    catch { return false; }
}

Type guard

null

Try / catch

try
{
    BuildCommentTextFromRuns(runs);
}
catch (ArgumentException ex) when (ex.Message.StartsWith("comment runs: invalid JSON"))
{
    // surface parser offset to the user; do not retry with the same string
}

Prevention

When it happens

Trigger: Calling the comment API with runs='[{"text":"hi"},]' (trailing comma), runs='{text:1}' (single quotes), or any non-JSON text. JsonNode.Parse throws JsonException, caught and rethrown as ArgumentException.

Common situations: Generating runs JSON by string concatenation instead of a serializer; passing a Python/JS dict literal instead of JSON; shell quoting that strips double quotes around keys.

Understand the failure class

Related errors


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

Appendix: source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Helpers.Node.cs:979

            // Non-generic Add(JsonNode) — the generic Add<T> overload carries
            // RequiresUnreferencedCode (IL2026) though it never serializes a JsonNode.
            arr.Add((System.Text.Json.Nodes.JsonNode)o);
        }
        return arr.ToJsonString();
    }

    // Build a CommentText from a `runs=<json array>` value, one <r> per run
    // carrying its own <rPr>. Run vocabulary mirrors rich-text cells
    // (bold/italic/strike/underline/superscript/subscript/size/color/font) so
    // the two paths share one input contract. Comment runs keep the Tahoma-9
    // indexed-81 default for facets a run leaves unspecified.
    internal static CommentText BuildCommentTextFromRuns(string runsJson)
    {
        System.Text.Json.Nodes.JsonArray? arr;
        try { arr = System.Text.Json.Nodes.JsonNode.Parse(runsJson) as System.Text.Json.Nodes.JsonArray; }
        catch (System.Text.Json.JsonException ex)
        {
            throw new ArgumentException($"comment runs: invalid JSON array — {ex.Message}");
        }
        if (arr == null)
            throw new ArgumentException("comment runs: value must be a JSON array");

        var ct = new CommentText();
        foreach (var item in arr)
        {
            if (item is not System.Text.Json.Nodes.JsonObject o) continue;
            var text = o["text"]?.GetValue<string>() ?? "";
            OfficeCli.Core.ParseHelpers.ValidateXmlText(text, "comment run text");

            var rPr = new RunProperties();
            bool RunBool(string key) => o[key] is { } n
                && (n.GetValueKind() == System.Text.Json.JsonValueKind.True
                    || (n.GetValueKind() == System.Text.Json.JsonValueKind.String && IsTruthy(n.GetValue<string>())));

            if (RunBool("bold")) rPr.AppendChild(new Bold());
            if (RunBool("italic")) rPr.AppendChild(new Italic());

View on GitHub (pinned to 1ced45e900)