iOfficeAI/OfficeCLI · error · System.ArgumentException

'runs' must be a JSON array of run objects.

Error message

'runs' must be a JSON array of run objects.

What it means

Thrown by ApplyRichTextToCell when the runs property parses as valid JSON but its root element is not an array. The code requires runs to be a JSON array of run objects (e.g. [{"text":"Hello","bold":"true"}]). A JSON object, string, or number at the root triggers this guard after JsonDocument.Parse succeeds but before array enumeration.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs:1440

        SharedStringTable sst;
        if (sstPart.SharedStringTable != null)
            sst = sstPart.SharedStringTable;
        else
        {
            sst = new SharedStringTable();
            sstPart.SharedStringTable = sst;
        }

        var ssi = new SharedStringItem();

        var gatheredRuns = new List<(string text, Dictionary<string, string> props)>();
        if (properties.TryGetValue("runs", out var runsJson) && !string.IsNullOrWhiteSpace(runsJson))
        {
            try
            {
                using var jdoc = System.Text.Json.JsonDocument.Parse(runsJson);
                if (jdoc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)
                    throw new ArgumentException("'runs' must be a JSON array of run objects.");
                foreach (var el in jdoc.RootElement.EnumerateArray())
                {
                    if (el.ValueKind != System.Text.Json.JsonValueKind.Object)
                        throw new ArgumentException("Each run in 'runs' must be a JSON object.");
                    string text = "";
                    var pd = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                    foreach (var p in el.EnumerateObject())
                    {
                        var sv = p.Value.ValueKind switch
                        {
                            System.Text.Json.JsonValueKind.True => "true",
                            System.Text.Json.JsonValueKind.False => "false",
                            System.Text.Json.JsonValueKind.Null => "",
                            System.Text.Json.JsonValueKind.Number => p.Value.GetRawText(),
                            _ => p.Value.GetString() ?? ""
                        };
                        if (p.NameEquals("text")) text = sv;
                        else pd[p.Name] = sv;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Wrap run objects in a JSON array: runs="[{\"text\":\"x\"}]".
  2. For a single run, still use the array form with one element.
  3. Use the legacy run1=text:prop=val syntax if building JSON arrays is inconvenient.

Example fix

// before
props["runs"] = "{\"text\":\"Hello\",\"bold\":\"true\"}";

// after
props["runs"] = "[{\"text\":\"Hello\",\"bold\":\"true\"}]";
Defensive patterns

Strategy: validation

Validate before calling

if (props.TryGetValue("runs", out var runsJson) && !string.IsNullOrWhiteSpace(runsJson))
{
    using var jdoc = System.Text.Json.JsonDocument.Parse(runsJson);
    if (jdoc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)
        throw new InvalidOperationException("runs must be a JSON array");
}
handler.Add(parentPath, "richtext", pos, props);

Type guard

static bool RunsJsonIsArray(string? json)
{
    if (string.IsNullOrWhiteSpace(json)) return true;
    using var d = System.Text.Json.JsonDocument.Parse(json);
    return d.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array;
}

Prevention

When it happens

Trigger: properties["runs"]="{\"text\":\"x\"}" (a single object instead of an array), or runs="\"text\"" (a JSON string), or runs="42". Any valid JSON whose ValueKind is not Array. Malformed JSON hits error 494 instead.

Common situations: User wraps a single run in {} instead of []. JSON serializer configured to emit an object for a single-element collection. Copy-pasting a single run spec where an array is expected.

Related errors


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