angular/components · error

MatSelectionColumn: missing parent table

Error message

MatSelectionColumn: missing parent table

What it means

MatSelectionColumn must register its column definition with a parent table via _table.addColumnDef. In dev mode, when the parent table reference is missing (the column is not inside the expected table element), ngOnInit throws this error. Without registration the column's cells would never render, so the library fails fast.

Source

Thrown at src/material-experimental/selection/selection-column.ts:106

  @ViewChild(MatColumnDef, {static: true}) private readonly _columnDef!: MatColumnDef;
  @ViewChild(MatCellDef, {static: true}) private readonly _cell!: MatCellDef;
  @ViewChild(MatHeaderCellDef, {static: true})
  private readonly _headerCell!: MatHeaderCellDef;

  ngOnInit() {
    if (!this.selection && (typeof ngDevMode === 'undefined' || ngDevMode)) {
      throw Error('MatSelectionColumn: missing MatSelection in the parent');
    }

    this._syncColumnDefName();

    if (this._table) {
      this._columnDef.cell = this._cell;
      this._columnDef.headerCell = this._headerCell;
      this._table.addColumnDef(this._columnDef);
    } else if (typeof ngDevMode === 'undefined' || ngDevMode) {
      throw Error('MatSelectionColumn: missing parent table');
    }
  }

  ngOnDestroy() {
    if (this._table) {
      this._table.removeColumnDef(this._columnDef);
    }
  }

  private _syncColumnDefName() {
    if (this._columnDef) {
      this._columnDef.name = this._name;
    }
  }
}

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Wrap the selection column in the correct parent table element (mat-selection-table or equivalent) that injects/registers column defs.
  2. Check that the column directive's parent selector actually matches your table (attribute/element selectors must line up).
  3. Fix template structure after refactors — the column must be a direct descendant of the table providing the token.
  4. Ensure the required experimental module is imported so the parent table directive is active.

Example fix

// before
<div class="my-table">
  <th mat-selection-column>Select</th>
</div>

// after
<mat-selection-table>
  <th mat-selection-column>Select</th>
</mat-selection-table>
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard before placing the column in dynamic templates:
const tableEl = hostEl.nativeElement.closest('mat-selection-table');
if (!tableEl) throw new Error('mat-selection-column must be inside a selection table');

Type guard

function hasSelectionTableParent(el: HTMLElement): boolean {
  return el.closest('mat-selection-table') !== null;
}

Try / catch

// Structural dev-mode error; resolve at template level, catch only for reporting:
try {
  this.viewContainerRef.createComponent(SelectionColumnComponent);
} catch (e) {
  if (String(e.message).includes('missing parent table')) {
    console.error('Selection column requires a parent table');
  } else throw e;
}

Prevention

When it happens

Trigger: Using `<mat-selection-column>` outside any parent table that implements addColumnDef/removeColumnDef — e.g. inside a plain `<table>` or standalone in a component template — so `this._table` is null in ngOnInit while ngDevMode is enabled.

Common situations: Rendering the column in a component that isn't inside the selection table; conditionally restructuring templates so the column's parent changes; migration to a different table wrapper that doesn't provide the table token.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/3ec67cdc8aae2d48. Report an issue: GitHub.