iOfficeAI/OfficeCLI · error · ArgumentException

table ref '{rangeRef}' has 1 row; tables must have at least

Error message

table ref '{rangeRef}' has 1 row; tables must have at least 2 rows (header + 1 data row). Pass headerRow=false for a data-only single-row table.

What it means

Thrown by AddTable's i103 guard when headerRow is true (the default) and the table ref covers exactly one row. A header-only ref (e.g. A1:C1) produces an <autoFilter> that Excel rejects with 'Removed Feature: AutoFilter', which cascades and drops the whole table on open. The handler requires at least a header plus one data row unless headerRow=false is set for a data-only single-row table.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Tables.cs:1216

                    if (!anyNonEmpty) break;
                    endRow = probeRow;
                    probeRow++;
                }
                rangeRef = $"{startCol}{startRow}:{endCol}{endRow}";
            }
        }

        // i103: when headerRow=true (the default) the table ref must cover
        // at least 2 rows — header plus one data row. A header-only ref
        // (e.g. A1:C1) produces an <autoFilter> that Excel rejects with
        // "Removed Feature: AutoFilter from /xl/tables/tableN.xml part",
        // which cascades to drop the whole table on file open. Reject up
        // front with a clear message instead of letting Excel silently
        // strip the table. headerRow=false is allowed to be a single
        // (data-only) row.
        if (hasHeader && startRow == endRow)
        {
            throw new ArgumentException(
                $"table ref '{rangeRef}' has 1 row; tables must have at least 2 rows " +
                "(header + 1 data row). Pass headerRow=false for a data-only single-row table.");
        }

        // CONSISTENCY(table-totalrow): a:totalsRowShown MUST point at a row
        // OUTSIDE the data area. Previously we reused endRow as the totals
        // row, which overwrote whatever data lived on that last row. Expand
        // the ref by one row so the totals row is appended below the data
        // instead of stamping over it.
        if (hasTotalRow)
        {
            endRow += 1;
            rangeRef = $"{startCol}{startRow}:{endCol}{endRow}";
        }

        string[] colNames;
        if (properties.TryGetValue("columns", out var tblColsStr))
        {

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Extend the ref to at least two rows (header + data), e.g. ref=A1:C2.
  2. If a single data-only row is intended, pass headerRow=false.
  3. Verify startRow equals endRow is the actual condition; any 2+ row ref passes.

Example fix

// before
add /Sheet1/table --prop ref=A1:C1
// after (header + data)
add /Sheet1/table --prop ref=A1:C2
// or data-only
add /Sheet1/table --prop ref=A1:C1 --prop headerRow=false
Defensive patterns

Strategy: validation

Validate before calling

// Validate a table ref has >=2 rows when headerRow is true (default).
static bool TryValidateHeaderRef(string rangeRef, bool headerRow, out string error)
{
    error = null;
    if (!headerRow) return true;
    var (startRow, endRow) = ParseRows(rangeRef); // pseudo: extract numeric rows
    if (startRow == endRow)
    {
        error = $"table ref '{rangeRef}' has 1 row; pass headerRow=false for data-only.";
        return false;
    }
    return true;
}

Try / catch

try { handler.Add(parentPath, "table", null, props); }
catch (ArgumentException ex) when (ex.Message.Contains("tables must have at least 2 rows"))
{ /* extend ref to 2+ rows or set headerRow=false, then retry */ }

Prevention

When it happens

Trigger: Calling Add('/Sheet1/table', ...) with ref=A1:C1 (one row) and no headerRow=false, i.e. relying on the default headerRow=true.

Common situations: Building a table from a header-only template, auto-sizing the ref to the used header row, or intending a single-row data table.

Related errors


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