iOfficeAI/OfficeCLI · error · ArgumentException

Invalid 'cols' value: '{colsStr}'. Expected a positive integ

Error message

Invalid 'cols' value: '{colsStr}'. Expected a positive integer (number of columns to create).

What it means

AddRow's `cols` property pre-materializes that many cells in the new row (so you can fill them in one shot via c1=/c2=/...). It must be a strictly positive integer. A zero or negative value would loop zero/invalid times and a non-integer would be meaningless for a column count, so it is rejected up front.

Source

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

        {
            newRow.Hidden = addRowHidden.Equals("true", StringComparison.OrdinalIgnoreCase)
                || addRowHidden == "1" || addRowHidden.Equals("yes", StringComparison.OrdinalIgnoreCase);
        }
        // CONSISTENCY(add-set-symmetry): accept outline/group + collapsed at
        // creation, mirroring SetRow (ExcelHandler.Set.cs L2823-2832).
        if (parsedRowOutline is { } rowOutlineVal)
            newRow.OutlineLevel = rowOutlineVal;
        if (properties.TryGetValue("collapsed", out var addRowCollapsed))
        {
            newRow.Collapsed = addRowCollapsed.Equals("true", StringComparison.OrdinalIgnoreCase)
                || addRowCollapsed == "1" || addRowCollapsed.Equals("yes", StringComparison.OrdinalIgnoreCase);
        }

        // Create cells if cols specified
        if (properties.TryGetValue("cols", out var colsStr))
        {
            if (!int.TryParse(colsStr, out var cols) || cols <= 0)
                throw new ArgumentException($"Invalid 'cols' value: '{colsStr}'. Expected a positive integer (number of columns to create).");
            // CONSISTENCY(table-row-cN): pptx AddRow accepts c1=/c2=/... to
            // populate the new row's cells (PowerPointHandler.Add.Table.cs
            // L332). Mirror it here so xlsx `add row --prop cols=N c1=...`
            // is a one-shot row create + fill instead of needing N follow-up
            // cell Sets. Only materialize a <c> when the caller actually
            // supplied content for that column — pre-emitting empty <c r=...>
            // shells would diverge from Excel's stored form (empty cells are
            // simply absent) and make Get("/Sheet/An") report "" instead of
            // "(empty)".
            for (int c = 0; c < cols; c++)
            {
                if (!properties.TryGetValue($"c{c + 1}", out var cellText) || cellText == null)
                    continue;
                var colLetter = IndexToColumnName(c + 1);
                EnsureCellValueLength(cellText, $"{colLetter}{rowIdx}");
                var safe = OfficeCli.Core.PivotTableHelper.SanitizeXmlText(cellText);
                var newCell = new Cell
                {

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Omit `cols` entirely when you do not need pre-created cells — the row is still created, and cells appear only where c1=/c2=... content is supplied.
  2. Pass a positive integer equal to the number of cells you intend to populate.
  3. Guard dynamic counts: if the computed cols is <=0, skip the Add or use a minimum of 1.

Example fix

// before
handler.Add("/Sheet1", "row", null, new() { ["cols"] = colCount.ToString() });
// after
if (colCount > 0)
    handler.Add("/Sheet1", "row", null, new() { ["cols"] = colCount.ToString(), ["c1"] = val });
else
    handler.Add("/Sheet1", "row", null, new());
Defensive patterns

Strategy: validation

Validate before calling

if (props.TryGetValue("cols", out var c) && (!int.TryParse(c, out var n) || n <= 0))
    props.Remove("cols"); // or throw, depending on intent
h.Add(sheet, "row", pos, props);

Type guard

static bool IsValidColCount(string s) => int.TryParse(s, out var n) && n > 0;

Try / catch

try { h.Add(sheet, "row", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("'cols' value"))
{ /* default to omitting cols or using 1 */ }

Prevention

When it happens

Trigger: Add("/Sheet1","row",pos,{["cols"]="0"}); cols="-3"; cols="2.5" (fails int.TryParse); cols="three" (not numeric); cols="" (fails TryParse).

Common situations: Computing cols from a dynamic column count that can be 0 for an empty record; passing a floating-point column count; a templated call that left cols unset and defaulted to empty.

Related errors


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