{"record":{"id":"3b8190ea7934adf8","repo":"iOfficeAI/OfficeCLI","slug":"each-run-in-runs-must-be-a-json-object","errorCode":null,"errorMessage":"Each run in 'runs' must be a JSON object.","messagePattern":"Each run in 'runs' must be a JSON object\\.","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":1444,"sourceCode":"        {\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;\n                    }\n                    OfficeCli.Core.ParseHelpers.ValidateXmlText(text, \"richtext run text\");\n                    gatheredRuns.Add((text, pd));\n                }","sourceCodeStart":1426,"sourceCodeEnd":1462,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L1426-L1462","documentation":"Thrown by ApplyRichTextToCell while enumerating the runs JSON array: one of the array's elements is not a JSON object. Each run must be an object carrying a text field and optional style properties. A string, number, or nested array element triggers this guard during EnumerateArray.","triggerScenarios":"properties[\"runs\"]=\"[\\\"Hello\\\",42]\" or runs=\"[[{...}]]\". Any array element whose ValueKind is not Object. The check runs per element, so the first non-object element throws.","commonSituations":"User passes an array of plain strings instead of objects. JSON built by joining text values without wrapping each in {}. A serializer that flattens run specs.","solutions":["Make every array element an object: runs=\"[{\\\"text\\\":\\\"a\\\"},{\\\"text\\\":\\\"b\\\"}]\".","If you have plain strings, wrap each as {\"text\": \"<string>\"} before serializing.","Switch to the legacy run1/run2 numbered syntax for ad-hoc multi-run input."],"exampleFix":"// before\nprops[\"runs\"] = \"[\\\"Hello\\\",\\\"World\\\"]\";\n\n// after\nprops[\"runs\"] = \"[{\\\"text\\\":\\\"Hello\\\"},{\\\"text\\\":\\\"World\\\"}]\";","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    foreach (var el in jdoc.RootElement.EnumerateArray())\n        if (el.ValueKind != System.Text.Json.JsonValueKind.Object)\n            throw new InvalidOperationException(\"each run must be a JSON object\");\n}\nhandler.Add(parentPath, \"richtext\", pos, props);","typeGuard":"static bool RunsJsonAllObjects(string? json)\n{\n    if (string.IsNullOrWhiteSpace(json)) return true;\n    using var d = System.Text.Json.JsonDocument.Parse(json);\n    if (d.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array) return false;\n    foreach (var el in d.RootElement.EnumerateArray())\n        if (el.ValueKind != System.Text.Json.JsonValueKind.Object) return false;\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Define a run record type and serialize a list of records so elements are always objects.","Validate each element's kind before invoking Add.","Avoid hand-building JSON strings for run arrays."],"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"}