{"record":{"id":"61b7a69832e069a3","repo":"iOfficeAI/OfficeCLI","slug":"comment-runs-value-must-be-a-json-array","errorCode":null,"errorMessage":"comment runs: value must be a JSON array","messagePattern":"comment runs: value must be a JSON array","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Helpers.Node.cs","lineNumber":982,"sourceCode":"        }\n        return arr.ToJsonString();\n    }\n\n    // Build a CommentText from a `runs=<json array>` value, one <r> per run\n    // carrying its own <rPr>. Run vocabulary mirrors rich-text cells\n    // (bold/italic/strike/underline/superscript/subscript/size/color/font) so\n    // the two paths share one input contract. Comment runs keep the Tahoma-9\n    // indexed-81 default for facets a run leaves unspecified.\n    internal static CommentText BuildCommentTextFromRuns(string runsJson)\n    {\n        System.Text.Json.Nodes.JsonArray? arr;\n        try { arr = System.Text.Json.Nodes.JsonNode.Parse(runsJson) as System.Text.Json.Nodes.JsonArray; }\n        catch (System.Text.Json.JsonException ex)\n        {\n            throw new ArgumentException($\"comment runs: invalid JSON array — {ex.Message}\");\n        }\n        if (arr == null)\n            throw new ArgumentException(\"comment runs: value must be a JSON array\");\n\n        var ct = new CommentText();\n        foreach (var item in arr)\n        {\n            if (item is not System.Text.Json.Nodes.JsonObject o) continue;\n            var text = o[\"text\"]?.GetValue<string>() ?? \"\";\n            OfficeCli.Core.ParseHelpers.ValidateXmlText(text, \"comment run text\");\n\n            var rPr = new RunProperties();\n            bool RunBool(string key) => o[key] is { } n\n                && (n.GetValueKind() == System.Text.Json.JsonValueKind.True\n                    || (n.GetValueKind() == System.Text.Json.JsonValueKind.String && IsTruthy(n.GetValue<string>())));\n\n            if (RunBool(\"bold\")) rPr.AppendChild(new Bold());\n            if (RunBool(\"italic\")) rPr.AppendChild(new Italic());\n            if (RunBool(\"strike\")) rPr.AppendChild(new Strike());\n            var uStr = o[\"underline\"]?.GetValue<string>();\n            if (!string.IsNullOrEmpty(uStr) && !string.Equals(uStr, \"none\", StringComparison.OrdinalIgnoreCase))","sourceCodeStart":964,"sourceCodeEnd":1000,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Helpers.Node.cs#L964-L1000","documentation":"Thrown by BuildCommentTextFromRuns when JsonNode.Parse succeeds but the result is not a JsonArray (e.g. it parsed as a JSON object, string, number, or scalar). The runs contract requires an array of run objects.","triggerScenarios":"runs='{\"text\":\"hi\"}' (a JSON object, not array), runs=\"\\\"hello\\\"\" (a JSON string), runs='42' (a JSON number), or runs='true'. All parse fine but cast to JsonArray yields null.","commonSituations":"Passing a single run object instead of a one-element array; reusing a schema that wraps runs in an object; sending the text payload directly instead of an array wrapper.","solutions":["Wrap the value in an array: runs='[{...}]' even for a single run.","Validate ValueKind == Array before sending (see validationCode).","Re-check the schema example — runs is always a top-level JSON array, each element an object with at least a 'text' key."],"exampleFix":"// before\nstring runs = \"{\\\"text\\\":\\\"hi\\\"}\"; // object, not array\n// after\nstring runs = \"[{\\\"text\\\":\\\"hi\\\"}]\"; // array of one run","handlingStrategy":"validation","validationCode":"static bool IsRunsArray(string runsJson)\n{\n    try\n    {\n        using var doc = System.Text.Json.JsonDocument.Parse(runsJson);\n        return doc.RootElement.ValueKind == System.Text.Json.JsonValueKind.Array;\n    }\n    catch { return false; }\n}","typeGuard":"null","tryCatchPattern":"try { BuildCommentTextFromRuns(runs); }\ncatch (ArgumentException ex) when (ex.Message == \"comment runs: value must be a JSON array\")\n{ /* wrap single object into array, then retry */ }","preventionTips":["runs is an ARRAY of run objects — a bare object or scalar is rejected.","Schema-check the producer: each element should be an object, non-object elements are silently skipped.","Confirm the leading '[' and trailing ']' survive shell/JSON escaping."],"tags":["json","comments","excel","input-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}