{"record":{"id":"68a1041106009e4d","repo":"angular/components","slug":"missing-definitions-for-header-footer-and-row-c","errorCode":null,"errorMessage":"Missing definitions for header, footer, and row; cannot determine which columns should be rendered.","messagePattern":"Missing definitions for header, footer, and row; cannot determine which columns should be rendered\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cdk/table/table.ts","lineNumber":1008,"sourceCode":"  /** Whether the table has all the information to start rendering. */\n  private _canRender(): boolean {\n    return this._hasAllOutlets && this._hasInitialized;\n  }\n\n  /** Renders the table if its state has changed. */\n  private _render(): void {\n    // Cache the row and column definitions gathered by ContentChildren and programmatic injection.\n    this._cacheRowDefs();\n    this._cacheColumnDefs();\n\n    // Make sure that the user has at least added header, footer, or data row def.\n    if (\n      !this._headerRowDefs.length &&\n      !this._footerRowDefs.length &&\n      !this._rowDefs.length &&\n      (typeof ngDevMode === 'undefined' || ngDevMode)\n    ) {\n      throw getTableMissingRowDefsError();\n    }\n\n    // Render updates if the list of columns have been changed for the header, row, or footer defs.\n    const columnsChanged = this._renderUpdatedColumns();\n    const rowDefsChanged = columnsChanged || this._headerRowDefChanged || this._footerRowDefChanged;\n    // Ensure sticky column styles are reset if set to `true` elsewhere.\n    this._stickyColumnStylesNeedReset = this._stickyColumnStylesNeedReset || rowDefsChanged;\n    this._forceRecalculateCellWidths = rowDefsChanged;\n\n    // If the header row definition has been changed, trigger a render to the header row.\n    if (this._headerRowDefChanged) {\n      this._forceRenderHeaderRows();\n      this._headerRowDefChanged = false;\n    }\n\n    // If the footer row definition has been changed, trigger a render to the footer row.\n    if (this._footerRowDefChanged) {\n      this._forceRenderFooterRows();","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/table/table.ts#L990-L1026","documentation":"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).","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\n<table mat-table [dataSource]=data>\n  <ng-container matColumnDef=\"name\"><th mat-header-cell *matHeaderCellDef>Name</th><td mat-cell *matCellDef=\"let e\">{{e.name}}</td></ng-container>\n</table>\n// after\n<table mat-table [dataSource]=data>\n  <ng-container matColumnDef=\"name\"><th mat-header-cell *matHeaderCellDef>Name</th><td mat-cell *matCellDef=\"let e\">{{e.name}}</td></ng-container>\n  <tr mat-header-row *matHeaderRowDef=\"['name']\"></tr>\n  <tr mat-row *matRowDef=\"let row; columns: ['name'];\"></tr>\n</table>","handlingStrategy":"validation","validationCode":"const hasRowDefs =\n  !!document.querySelector('tr[matRowDef], tr[mat-header-row], tr[matHeaderRowDef]') ||\n  !!(templateRefs && templateRefs.some(t => /matRowDef|matHeaderRowDef/.test(t)));\nif (!hasRowDefs) throw new Error('Table requires a *matRowDef and *matHeaderRowDef');","typeGuard":"function hasTableRows(tpl: string): boolean {\n  return /matHeaderRowDef/.test(tpl) && /matRowDef/.test(tpl);\n}","tryCatchPattern":"try {\n  this.appRef.attachView(tableHostView);\n} catch (e) {\n  if (/Missing definitions for header, footer, and row/.test(e.message)) {\n    console.error('Add <tr mat-row *matRowDef> and <tr mat-header-row *matHeaderRowDef> to the table.');\n  }\n}","preventionTips":["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"],"tags":["angular","cdk-table","missing-row-def","template"],"backgroundTag":"table-missing-row-definitions","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}