Skip to content

fix(cdk/table): show a real error message instead of a crash when a table column is missing - #33698

Open
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/cdk-table-unknown-column-prod-error
Open

fix(cdk/table): show a real error message instead of a crash when a table column is missing#33698
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/cdk-table-unknown-column-prod-error

Conversation

@arturovt

Copy link
Copy Markdown
Contributor

Before: if a row used a column that wasn't defined, the app would crash in production with a confusing error like "Cannot read properties of undefined (reading 'headerCell')" — no mention of which column was the problem. This message only showed up in dev mode; in production you just got a raw, useless crash.

Now: the table always throws a clear error like Could not find column with id "column_a"., in both dev and production, so it's obvious what went wrong and which column to fix.

Added a test that forces production mode and checks the table gives the helpful error instead of crashing.

…able column is missing

Before: if a <cdk-table> row used a column that wasn't defined, the app
would crash in production with a confusing error like "Cannot read
properties of undefined (reading 'headerCell')" — no mention of which
column was the problem. This message only showed up in dev mode; in
production you just got a raw, useless crash.

Now: the table always throws a clear error like `Could not find
column with id "column_a".`, in both dev and production, so it's
obvious what went wrong and which column to fix.

Added a test that forces production mode and checks the table gives
the helpful error instead of crashing.
Comment thread src/cdk/table/table.ts
private _addStickyColumnStyles(rows: HTMLElement[], rowDef: BaseRowDef) {
const columnDefs = Array.from(rowDef?.columns || []).map(columnName => {
const columnDef = this._columnDefsByName.get(columnName);
if (!columnDef && (typeof ngDevMode === 'undefined' || ngDevMode)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intent here was that the columns likely aren't changing between dev and production so we don't need to do this assertion in production.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah totally get that, and agree we don't want an assertion running on
every render just for something that "shouldn't" happen.

but fwiw this literally hit us in prod and we never once saw it in dev,
so the columns-dont-change-between-envs assumption kinda broke down for
us here lol. and when it does happen the error you get is just "cannot
read properties of undefined (reading headerCell)" with a stack that's
100% internal cdk frames - no column name, nothing. took us a while to
even figure out which table/column was the problem.

what if instead of bringing back the assertion we just wrap the actual
dereference in a try/catch and only build the nicer message if it
throws? like:

  try {
    return column.headerCell.template;
  } catch (error) {
    throw new error with some code (columnId);
  }

afaik try/catch is basically free in v8 as long as it doesn't actually
throw, so this shouldn't add the per-render cost you're worried about -
it only does anything in the case that was already about to blow up
anyway. just makes the blow up say something useful instead of a bare
TypeError.

happy to gate it behind prod-only too if you want dev to keep the exact
message it has now, just seemed silly to keep the error a total mystery
for anyone hitting in apps.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is how it looks in prod which isn't very friendly:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants