{"record":{"id":"f5ba262cb1a2e46b","repo":"iOfficeAI/OfficeCLI","slug":"calculatedfields-must-be-a-json-array","errorCode":null,"errorMessage":"'calculatedFields' must be a JSON array","messagePattern":"'calculatedFields' must be a JSON array","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/PivotTableHelper.Definition.cs","lineNumber":1715,"sourceCode":"    ///   calculatedField=Name:=Formula\n    ///   calculatedField=Name:Formula     (leading '=' optional)\n    ///   calculatedField1=..., calculatedField2=...\n    ///   calculatedFields=[{\"name\":\"X\",\"formula\":\"...\"}, ...]  (JSON)\n    /// </summary>\n    private static List<(string name, string formula)> ParseCalculatedFieldSpecs(\n        Dictionary<string, string> properties)\n    {\n        var result = new List<(string, string)>();\n\n        // JSON form first — higher fidelity when user wants multiple specs.\n        if (properties.TryGetValue(\"calculatedFields\", out var jsonRaw)\n            && !string.IsNullOrWhiteSpace(jsonRaw))\n        {\n            try\n            {\n                using var doc = System.Text.Json.JsonDocument.Parse(jsonRaw);\n                if (doc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)\n                    throw new ArgumentException(\"'calculatedFields' must be a JSON array\");\n                foreach (var el in doc.RootElement.EnumerateArray())\n                {\n                    if (el.ValueKind != System.Text.Json.JsonValueKind.Object)\n                        throw new ArgumentException(\"each calculatedFields entry must be a JSON object\");\n                    string? name = null, formula = null;\n                    foreach (var p in el.EnumerateObject())\n                    {\n                        if (p.NameEquals(\"name\")) name = p.Value.GetString();\n                        else if (p.NameEquals(\"formula\")) formula = p.Value.GetString();\n                    }\n                    if (name != null && formula != null)\n                        result.Add((name, formula));\n                }\n            }\n            catch (System.Text.Json.JsonException ex)\n            {\n                throw new ArgumentException($\"invalid JSON for calculatedFields: {ex.Message}\");\n            }","sourceCodeStart":1697,"sourceCodeEnd":1733,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/PivotTableHelper.Definition.cs#L1697-L1733","documentation":"The 'calculatedFields' property is parsed as JSON and the parser requires its root element to be a JSON array. Passing any other top-level JSON shape (object, string, number) is rejected up front rather than silently coerced, because the helper expects a list of {name,formula} objects. This keeps malformed input from producing a partial or wrong set of calc fields.","triggerScenarios":"Passing a single JSON object instead of an array: calculatedFields={\"name\":\"X\",\"formula\":\"=A1\"}; passing a JSON string or number like calculatedFields=\"\\\"X\\\"\" or calculatedFields=42; passing a nested array shape the parser does not expect.","commonSituations":"User copy-pastes one object from documentation that shows the array element rather than the whole array; tooling that emits a single object when there is only one field; misunderstanding that 'calculatedFields' (plural, JSON) differs from 'calculatedField' (singular, colon form).","solutions":["Wrap the object(s) in an array: calculatedFields=[{\"name\":\"X\",\"formula\":\"=A1\"}]","For a single field, prefer the singular colon form: calculatedField=X:=A1","Validate the JSON shape with a quick parse before submitting if you generate it programmatically"],"exampleFix":"// before\ncalculatedFields=\"{\\\"name\\\":\\\"X\\\",\\\"formula\\\":\\\"=A1\\\"}\"\n// after\ncalculatedFields=\"[{\\\"name\\\":\\\"X\\\",\\\"formula\\\":\\\"=A1\\\"}]\"","handlingStrategy":"validation","validationCode":"using var doc = System.Text.Json.JsonDocument.Parse(jsonRaw);\nif (doc.RootElement.ValueKind != JsonValueKind.Array)\n    throw new InvalidOperationException(\"calculatedFields must be a JSON array\");","typeGuard":"static bool IsJsonArray(string json)\n{\n    try { return JsonDocument.Parse(json).RootElement.ValueKind == JsonValueKind.Array; }\n    catch { return false; }\n}","tryCatchPattern":"try { AddCalculatedFields(props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must be a JSON array\"))\n{ /* rewrite the value as an array or switch to the singular prop */ }","preventionTips":["Use the singular calculatedField prop for single fields to avoid JSON shape issues","Validate JSON shape with a quick parse before submitting","Generate JSON from a serializer rather than hand-writing it"],"tags":["pivottable","calculated-field","json","argument-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}