{"record":{"id":"5410d87b3d8a8c40","repo":"iOfficeAI/OfficeCLI","slug":"invalid-json-for-runs-jex-message","errorCode":null,"errorMessage":"Invalid JSON for 'runs': {jex.Message}","messagePattern":"Invalid JSON for 'runs': (.+?)","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":1466,"sourceCode":"                    {\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                }\n            }\n            catch (System.Text.Json.JsonException jex)\n            {\n                throw new ArgumentException($\"Invalid JSON for 'runs': {jex.Message}\");\n            }\n        }\n        else\n        {\n            var runKeys = properties.Keys\n                .Where(k => k.StartsWith(\"run\", StringComparison.OrdinalIgnoreCase) && k.Length > 3 &&\n                            int.TryParse(k.AsSpan(3), out _))\n                .OrderBy(k => int.Parse(k.AsSpan(3).ToString()))\n                .ToList();\n            foreach (var runKey in runKeys)\n            {\n                var runVal = properties[runKey];\n                var colonIdx = runVal.IndexOf(':');\n                string runText;\n                string[] runProps;\n                if (colonIdx >= 0)\n                {\n                    runText = runVal[..colonIdx];","sourceCodeStart":1448,"sourceCodeEnd":1484,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L1448-L1484","documentation":"Thrown by ApplyRichTextToCell when the runs property is not valid JSON at all. JsonDocument.Parse raises a JsonException, which is caught and rewrapped as an ArgumentException with the parser's message. This fires before the array/object structure checks (492, 493), so any syntactically invalid JSON lands here.","triggerScenarios":"properties[\"runs\"]=\"text:Hello;bold:true\" (legacy syntax mistakenly put in runs=), or runs=\"{text\" (truncated), or runs=\"'single quotes'\". Any input that is not whitespace, not valid JSON, and not empty. Empty/whitespace runs skips the JSON branch entirely and falls to legacy runN parsing.","commonSituations":"User conflates the runs= JSON syntax with the legacy run1=text:prop=val syntax. Trailing commas, single quotes, unescaped quotes in the JSON. A shell quoting error that truncates the JSON.","solutions":["If you meant legacy syntax, use run1=text:bold=true numbered keys instead of runs=.","Validate the JSON with a linter before passing it; ensure double quotes and no trailing commas.","Build the JSON with a serializer (System.Text.Json.JsonSerializer.Serialize) rather than hand-concatenating strings."],"exampleFix":"// before\nprops[\"runs\"] = \"text:Hello;bold:true\"; // legacy syntax in wrong key\n\n// after\nprops[\"run1\"] = \"text:Hello;bold=true\"; // legacy numbered syntax","handlingStrategy":"try-catch","validationCode":"if (props.TryGetValue(\"runs\", out var runsJson) && !string.IsNullOrWhiteSpace(runsJson))\n{\n    try { using var jdoc = System.Text.Json.JsonDocument.Parse(runsJson); }\n    catch (System.Text.Json.JsonException) { throw new InvalidOperationException(\"runs is not valid JSON\"); }\n}\nhandler.Add(parentPath, \"richtext\", pos, props);","typeGuard":"static bool RunsJsonParses(string? json)\n{\n    if (string.IsNullOrWhiteSpace(json)) return true;\n    try { using var _ = System.Text.Json.JsonDocument.Parse(json); return true; }\n    catch (System.Text.Json.JsonException) { return false; }\n}","tryCatchPattern":"try { handler.Add(parentPath, \"richtext\", pos, props); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Invalid JSON for 'runs'\"))\n{ /* fix the JSON or switch to run1= legacy syntax */ }","preventionTips":["Build runs JSON with JsonSerializer.Serialize rather than string concatenation.","If the input is legacy syntax (text:prop=val), use the run1= key instead of runs=.","Run the JSON through a linter when accepting it from user input or a shell."],"tags":["excel","ooxml","richtext","json","parse-error","argument"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}