{"record":{"id":"e870b2daaa529168","repo":"iOfficeAI/OfficeCLI","slug":"runs-must-be-a-json-array-of-run-objects","errorCode":null,"errorMessage":"'runs' must be a JSON array of run objects.","messagePattern":"'runs' must be a JSON array of run objects\\.","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":1440,"sourceCode":"        SharedStringTable sst;\n        if (sstPart.SharedStringTable != null)\n            sst = sstPart.SharedStringTable;\n        else\n        {\n            sst = new SharedStringTable();\n            sstPart.SharedStringTable = sst;\n        }\n\n        var ssi = new SharedStringItem();\n\n        var gatheredRuns = new List<(string text, Dictionary<string, string> props)>();\n        if (properties.TryGetValue(\"runs\", out var runsJson) && !string.IsNullOrWhiteSpace(runsJson))\n        {\n            try\n            {\n                using var jdoc = System.Text.Json.JsonDocument.Parse(runsJson);\n                if (jdoc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)\n                    throw new ArgumentException(\"'runs' must be a JSON array of run objects.\");\n                foreach (var el in jdoc.RootElement.EnumerateArray())\n                {\n                    if (el.ValueKind != System.Text.Json.JsonValueKind.Object)\n                        throw new ArgumentException(\"Each run in 'runs' must be a JSON object.\");\n                    string text = \"\";\n                    var pd = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);\n                    foreach (var p in el.EnumerateObject())\n                    {\n                        var sv = p.Value.ValueKind switch\n                        {\n                            System.Text.Json.JsonValueKind.True => \"true\",\n                            System.Text.Json.JsonValueKind.False => \"false\",\n                            System.Text.Json.JsonValueKind.Null => \"\",\n                            System.Text.Json.JsonValueKind.Number => p.Value.GetRawText(),\n                            _ => p.Value.GetString() ?? \"\"\n                        };\n                        if (p.NameEquals(\"text\")) text = sv;\n                        else pd[p.Name] = sv;","sourceCodeStart":1422,"sourceCodeEnd":1458,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L1422-L1458","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wrap run objects in a JSON array: runs=\"[{\\\"text\\\":\\\"x\\\"}]\".","For a single run, still use the array form with one element.","Use the legacy run1=text:prop=val syntax if building JSON arrays is inconvenient."],"exampleFix":"// before\nprops[\"runs\"] = \"{\\\"text\\\":\\\"Hello\\\",\\\"bold\\\":\\\"true\\\"}\";\n\n// after\nprops[\"runs\"] = \"[{\\\"text\\\":\\\"Hello\\\",\\\"bold\\\":\\\"true\\\"}]\";","handlingStrategy":"validation","validationCode":"if (props.TryGetValue(\"runs\", out var runsJson) && !string.IsNullOrWhiteSpace(runsJson))\n{\n    using var jdoc = System.Text.Json.JsonDocument.Parse(runsJson);\n    if (jdoc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)\n        throw new InvalidOperationException(\"runs must be a JSON array\");\n}\nhandler.Add(parentPath, \"richtext\", pos, props);","typeGuard":"static bool RunsJsonIsArray(string? json)\n{\n    if (string.IsNullOrWhiteSpace(json)) return true;\n    using var d = System.Text.Json.JsonDocument.Parse(json);\n    return d.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array;\n}","tryCatchPattern":null,"preventionTips":["Always serialize run collections with a JSON serializer that emits an array even for one element.","Validate the runs JSON shape before passing it to Add/Set.","Use the legacy run1= syntax for ad-hoc single runs to avoid JSON entirely."],"tags":["excel","ooxml","richtext","json","runs","argument"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}