{"record":{"id":"9b06c81d1081313c","repo":"iOfficeAI/OfficeCLI","slug":"literal-braces-around-a-formula-create-an","errorCode":null,"errorMessage":"Literal braces '{...}' around a formula create an Excel-rejected file. Use --prop arrayformula=... (without braces) to declare a CSE array formula.","messagePattern":"Literal braces '(.+?)' around a formula create an Excel-rejected file\\. Use --prop arrayformula=\\.\\.\\. \\(without braces\\) to declare a CSE array formula\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":619,"sourceCode":"                }\n                else if (!double.TryParse(safeValue, out var dbl) || !double.IsFinite(dbl))\n                    cell.DataType = new EnumValue<CellValues>(CellValues.String);\n                else\n                    // R-fuzz2-1: TryParse accepts spellings Excel's <v> parser\n                    // does not (\"+5\", \"1,234\", padded). Store the canonical\n                    // form; literal digits are preserved when already canonical.\n                    cell.CellValue = new CellValue(NormalizeNumericCellText(safeValue, dbl));\n            }\n        }\n        if (properties.TryGetValue(\"formula\", out var formula))\n        {\n            // Strip a leading '=' (formula-bar copy) and reject\n            // literal `{...}` array-formula wrapping — users must use\n            // the dedicated `arrayformula=` prop for that, since\n            // `<x:f>{=...}</x:f>` causes Excel to reject the file.\n            var fTrim = formula.TrimStart('=').Trim();\n            if (fTrim.StartsWith(\"{\") && fTrim.EndsWith(\"}\"))\n                throw new ArgumentException(\"Literal braces '{...}' around a formula create an Excel-rejected file. Use --prop arrayformula=... (without braces) to declare a CSE array formula.\");\n            RejectCrossWorkbookFormula(fTrim);\n            ValidateFormulaCellRefs(fTrim);\n            var addCellFormula = new CellFormula(Core.PivotTableHelper.SanitizeXmlText(Core.ModernFunctionQualifier.Qualify(Core.ModernFunctionQualifier.AutoQuoteSheetRefs(fTrim))));\n            // Dynamic-array functions (SORT/FILTER/UNIQUE/SEQUENCE/XLOOKUP/LET/etc.)\n            // carry t=\"array\" ref=\"<cellRef>\" on the cell-level CellFormula PLUS a\n            // cm cell-metadata index into an XLDAPR record (EnsureDynamicArrayMetadata)\n            // — t=\"array\" alone is a legacy CSE array locked to the anchor; the\n            // XLDAPR metadata is what makes Excel 365 spill. The anchor reference is\n            // the single cell being written; Excel recomputes the spill extent and\n            // fills adjacent cells at runtime.\n            if (Core.ModernFunctionQualifier.IsDynamicArrayFormula(fTrim) && cell.CellReference?.Value != null)\n            {\n                addCellFormula.FormulaType = CellFormulaValues.Array;\n                addCellFormula.Reference = cell.CellReference.Value;\n                EnsureDynamicArrayMetadata(cell);\n            }\n            // CONSISTENCY(value-child-uniqueness): clear any stale <is> so the\n            // cell never carries both a formula and an inline string (invalid","sourceCodeStart":601,"sourceCodeEnd":637,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L601-L637","documentation":"A CSE array formula must be declared with the `arrayformula=` property, which emits the correct OOXML (<f t=\"array\">). Wrapping the formula= text in literal braces (e.g. {=SUM(...)}) writes `<f>{=...}</f>`, which Excel rejects on open. This guard detects a formula that starts with '{' and ends with '}' after trimming the leading '=' and rejects it, directing the user to arrayformula=.","triggerScenarios":"Add(\"/Sheet1/A1\",\"cell\",pos,{[\"formula\"]=\"{=B1:B3*C1:C3}\"}); formula=\"{SUM(A1:A3)}\"; any formula= value that, after TrimStart('=').Trim(), is brace-wrapped.","commonSituations":"Copying a formula straight from the Excel formula bar where array formulas display with braces; following a tutorial that shows the braced form; forgetting that arrayformula= is the dedicated property.","solutions":["Use the arrayformula= property without braces: arrayformula=\"B1:B3*C1:C3\" (with or without leading '=').","If it is a normal (non-array) formula, remove the braces entirely and use formula=.","For a single-cell dynamic-array formula (SORT/FILTER/UNIQUE/etc.), you can also use formula= without braces — dynamic arrays do not need CSE wrapping."],"exampleFix":"// before\nhandler.Add(\"/Sheet1/A1\", \"cell\", null, new() { [\"formula\"] = \"{=B1:B3*C1:C3}\" });\n// after\nhandler.Add(\"/Sheet1/A1\", \"cell\", null, new() { [\"arrayformula\"] = \"B1:B3*C1:C3\" });","handlingStrategy":"validation","validationCode":"if (props.TryGetValue(\"formula\", out var f))\n{\n    var ft = f.TrimStart('=').Trim();\n    if (ft.StartsWith(\"{\") && ft.EndsWith(\"}\"))\n    {\n        props.Remove(\"formula\");\n        props[\"arrayformula\"] = ft.Trim('{', '}');\n    }\n}\nh.Add(parentPath, \"cell\", pos, props);","typeGuard":"static bool IsBraceWrappedFormula(string f)\n{ var t = f.TrimStart('=').Trim(); return t.StartsWith(\"{\") && t.EndsWith(\"}\"); }","tryCatchPattern":"try { h.Add(parentPath, \"cell\", pos, props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Literal braces\"))\n{ /* move text to arrayformula= without braces and retry */ }","preventionTips":["Always use the arrayformula= property for CSE array formulas.","Strip braces copied from the Excel formula bar before passing as formula=.","Dynamic-array functions (SORT/FILTER/etc.) work via plain formula= without braces."],"tags":["excel","xlsx","cell","formula","arrayformula","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}