spectreconsole/spectre.console · error · InvalidOperationException

Column spanning is not supported in table {rowType} rows.

Error message

Column spanning is not supported in table {rowType} rows.

What it means

TableRow is constructed privately; the internal Header(...) and Footer(...) factories pass isHeader/isFooter=true. The constructor scans its items and, if any TableCell has ColumnSpan > 1, throws InvalidOperationException naming the row type ('header' or 'footer'). This is the row-level enforcement that backs the TableColumn.Header/Footer setters.

Source

Thrown at src/Spectre.Console/Widgets/Table/TableRow.cs:45

    /// <summary>
    /// Initializes a new instance of the <see cref="TableRow"/> class.
    /// </summary>
    /// <param name="items">The row items.</param>
    public TableRow(IEnumerable<IRenderable> items)
        : this(items, false, false)
    {
    }

    private TableRow(IEnumerable<IRenderable> items, bool isHeader, bool isFooter)
    {
        _items = new List<IRenderable>(items ?? []);

        // Reject column spanning in header or footer rows
        if ((isHeader || isFooter) && _items.OfType<TableCell>().Any(cell => cell.ColumnSpan > 1))
        {
            var rowType = isHeader ? "header" : "footer";
            throw new InvalidOperationException($"Column spanning is not supported in table {rowType} rows.");
        }

        IsHeader = isHeader;
        IsFooter = isFooter;
    }

    internal static TableRow Header(IEnumerable<IRenderable> items)
    {
        return new TableRow(items, true, false);
    }

    internal static TableRow Footer(IEnumerable<IRenderable> items)
    {
        return new TableRow(items, false, true);
    }

    internal void Add(IRenderable item)
    {

View on GitHub (pinned to 0acc92fada)

Solutions

  1. Ensure header/footer rows contain only non-spanning renderables (plain Markup or non-TableCell IRenderables).
  2. Build header/footer cells from a separate, span-free source distinct from body cells.
  3. Reset or replace spanned TableCells before they enter a header/footer row.

Example fix

// before
var headerCells = new IRenderable[] { new TableCell("H").Span(2) };

// after
var headerCells = new IRenderable[] { new Markup("H1"), new Markup("H2") };
Defensive patterns

Strategy: validation

Validate before calling

bool HasSpanningCell(IEnumerable<IRenderable> cells) =>
    cells.OfType<TableCell>().Any(c => c.ColumnSpan > 1);
if (HasSpanningCell(headerOrFooterCells))
    throw new InvalidOperationException("Header/footer rows must not contain spanning cells.");

Type guard

static bool RowHasNoSpans(IEnumerable<IRenderable> cells) =>
    !cells.OfType<TableCell>().Any(c => c.ColumnSpan > 1);

Prevention

When it happens

Trigger: Internally when a header or footer row is built containing a TableCell with ColumnSpan > 1 — e.g. table via APIs that assemble header/footer rows from TableCell instances. Also reachable when a user constructs/inserts a spanning cell into a row later flagged as header/footer.

Common situations: Mixing spanned body cells into header/footer construction paths; library version changes that route the same cell list through the header/footer factory; reusing a cell collection for both header and body.

Related errors


AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13). Data as JSON: /api/errors/d5d740069c8478ef. Report an issue: GitHub.