angular/components · error
Missing definitions for header, footer, and row; cannot dete
Error message
Missing definitions for header, footer, and row; cannot determine which columns should be rendered.
What it means
The CDK table throws this when, after content initialization, it found no header row definitions (matHeaderRowDef/cdkHeaderRowDef), no footer row definitions, and no row definitions (matRowDef/cdkRowDef). Without at least one row definition the table cannot know which columns to render or how to project rows. It only runs in development mode (ngDevMode).
Source
Thrown at src/cdk/table/table.ts:1008
/** Whether the table has all the information to start rendering. */
private _canRender(): boolean {
return this._hasAllOutlets && this._hasInitialized;
}
/** Renders the table if its state has changed. */
private _render(): void {
// Cache the row and column definitions gathered by ContentChildren and programmatic injection.
this._cacheRowDefs();
this._cacheColumnDefs();
// Make sure that the user has at least added header, footer, or data row def.
if (
!this._headerRowDefs.length &&
!this._footerRowDefs.length &&
!this._rowDefs.length &&
(typeof ngDevMode === 'undefined' || ngDevMode)
) {
throw getTableMissingRowDefsError();
}
// Render updates if the list of columns have been changed for the header, row, or footer defs.
const columnsChanged = this._renderUpdatedColumns();
const rowDefsChanged = columnsChanged || this._headerRowDefChanged || this._footerRowDefChanged;
// Ensure sticky column styles are reset if set to `true` elsewhere.
this._stickyColumnStylesNeedReset = this._stickyColumnStylesNeedReset || rowDefsChanged;
this._forceRecalculateCellWidths = rowDefsChanged;
// If the header row definition has been changed, trigger a render to the header row.
if (this._headerRowDefChanged) {
this._forceRenderHeaderRows();
this._headerRowDefChanged = false;
}
// If the footer row definition has been changed, trigger a render to the footer row.
if (this._footerRowDefChanged) {
this._forceRenderFooterRows();View on GitHub (pinned to 0411926e7d)
Solutions
- Add a row definition inside the table: <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
- Add a header row definition: <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
- Ensure row/header/footer directives are direct projected children of the table so ContentChildren queries pick them up
- Verify the MatTableModule/CdkTableModule is imported so directives are recognized
Example fix
// before
<table mat-table [dataSource]=data>
<ng-container matColumnDef="name"><th mat-header-cell *matHeaderCellDef>Name</th><td mat-cell *matCellDef="let e">{{e.name}}</td></ng-container>
</table>
// after
<table mat-table [dataSource]=data>
<ng-container matColumnDef="name"><th mat-header-cell *matHeaderCellDef>Name</th><td mat-cell *matCellDef="let e">{{e.name}}</td></ng-container>
<tr mat-header-row *matHeaderRowDef="['name']"></tr>
<tr mat-row *matRowDef="let row; columns: ['name'];"></tr>
</table> Defensive patterns
Strategy: validation
Validate before calling
const hasRowDefs =
!!document.querySelector('tr[matRowDef], tr[mat-header-row], tr[matHeaderRowDef]') ||
!!(templateRefs && templateRefs.some(t => /matRowDef|matHeaderRowDef/.test(t)));
if (!hasRowDefs) throw new Error('Table requires a *matRowDef and *matHeaderRowDef'); Type guard
function hasTableRows(tpl: string): boolean {
return /matHeaderRowDef/.test(tpl) && /matRowDef/.test(tpl);
} Try / catch
try {
this.appRef.attachView(tableHostView);
} catch (e) {
if (/Missing definitions for header, footer, and row/.test(e.message)) {
console.error('Add <tr mat-row *matRowDef> and <tr mat-header-row *matHeaderRowDef> to the table.');
}
} Prevention
- Always include header-row and row def lines when scaffolding a mat-table
- Keep row defs as direct children of the table element
- Use a shared table snippet/component so row defs are never omitted
When it happens
Trigger: CdkTable.ngAfterContentInit lifecycle when this._headerRowDefs.length === 0 && this._footerRowDefs.length === 0 && this._rowDefs.length === 0. E.g. a <table mat-table> with columns declared but no <tr mat-row> or <tr mat-header-row> elements, or row defs placed outside the table content projection.
Common situations: Forgetting the <tr mat-row *matRowDef="let row; columns: displayedColumns;"> line after copy-pasting a table skeleton; defining rows in a component whose ContentChildren don't reach the table because of an intermediate component boundary; typos in directive selectors (e.g. matRowDefs).
Related errors
- Duplicate column definition name provided: "${columnDef.name
- Could not find column with id "${columnId}".
- Conditional row definitions via the `when` input are not sup
- Tree is using conflicting node types which can cause unexpec
- There can only be one default row without a when predicate f
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/68a1041106009e4d.
Report an issue: GitHub.