iOfficeAI/OfficeCLI · error · ArgumentException

Literal braces '{...}' around a formula create an Excel-reje

Error message

Literal braces '{...}' around a formula create an Excel-rejected file. Use --prop arrayformula=... (without braces) to declare a CSE array formula.

What it means

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=.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs:619

                }
                else if (!double.TryParse(safeValue, out var dbl) || !double.IsFinite(dbl))
                    cell.DataType = new EnumValue<CellValues>(CellValues.String);
                else
                    // R-fuzz2-1: TryParse accepts spellings Excel's <v> parser
                    // does not ("+5", "1,234", padded). Store the canonical
                    // form; literal digits are preserved when already canonical.
                    cell.CellValue = new CellValue(NormalizeNumericCellText(safeValue, dbl));
            }
        }
        if (properties.TryGetValue("formula", out var formula))
        {
            // Strip a leading '=' (formula-bar copy) and reject
            // literal `{...}` array-formula wrapping — users must use
            // the dedicated `arrayformula=` prop for that, since
            // `<x:f>{=...}</x:f>` causes Excel to reject the file.
            var fTrim = formula.TrimStart('=').Trim();
            if (fTrim.StartsWith("{") && fTrim.EndsWith("}"))
                throw new ArgumentException("Literal braces '{...}' around a formula create an Excel-rejected file. Use --prop arrayformula=... (without braces) to declare a CSE array formula.");
            RejectCrossWorkbookFormula(fTrim);
            ValidateFormulaCellRefs(fTrim);
            var addCellFormula = new CellFormula(Core.PivotTableHelper.SanitizeXmlText(Core.ModernFunctionQualifier.Qualify(Core.ModernFunctionQualifier.AutoQuoteSheetRefs(fTrim))));
            // Dynamic-array functions (SORT/FILTER/UNIQUE/SEQUENCE/XLOOKUP/LET/etc.)
            // carry t="array" ref="<cellRef>" on the cell-level CellFormula PLUS a
            // cm cell-metadata index into an XLDAPR record (EnsureDynamicArrayMetadata)
            // — t="array" alone is a legacy CSE array locked to the anchor; the
            // XLDAPR metadata is what makes Excel 365 spill. The anchor reference is
            // the single cell being written; Excel recomputes the spill extent and
            // fills adjacent cells at runtime.
            if (Core.ModernFunctionQualifier.IsDynamicArrayFormula(fTrim) && cell.CellReference?.Value != null)
            {
                addCellFormula.FormulaType = CellFormulaValues.Array;
                addCellFormula.Reference = cell.CellReference.Value;
                EnsureDynamicArrayMetadata(cell);
            }
            // CONSISTENCY(value-child-uniqueness): clear any stale <is> so the
            // cell never carries both a formula and an inline string (invalid

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use the arrayformula= property without braces: arrayformula="B1:B3*C1:C3" (with or without leading '=').
  2. If it is a normal (non-array) formula, remove the braces entirely and use formula=.
  3. 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.

Example fix

// before
handler.Add("/Sheet1/A1", "cell", null, new() { ["formula"] = "{=B1:B3*C1:C3}" });
// after
handler.Add("/Sheet1/A1", "cell", null, new() { ["arrayformula"] = "B1:B3*C1:C3" });
Defensive patterns

Strategy: validation

Validate before calling

if (props.TryGetValue("formula", out var f))
{
    var ft = f.TrimStart('=').Trim();
    if (ft.StartsWith("{") && ft.EndsWith("}"))
    {
        props.Remove("formula");
        props["arrayformula"] = ft.Trim('{', '}');
    }
}
h.Add(parentPath, "cell", pos, props);

Type guard

static bool IsBraceWrappedFormula(string f)
{ var t = f.TrimStart('=').Trim(); return t.StartsWith("{") && t.EndsWith("}"); }

Try / catch

try { h.Add(parentPath, "cell", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("Literal braces"))
{ /* move text to arrayformula= without braces and retry */ }

Prevention

When it happens

Trigger: Add("/Sheet1/A1","cell",pos,{["formula"]="{=B1:B3*C1:C3}"}); formula="{SUM(A1:A3)}"; any formula= value that, after TrimStart('=').Trim(), is brace-wrapped.

Common situations: 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.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/9b06c81d1081313c. Report an issue: GitHub.