Deep dive into the infamous ExpressionChangedAfterItHasBeenCheckedError in Angular
Tags: angular
Published: 2023-01-31 09:17:00

---
title: Deep dive into the infamous ExpressionChangedAfterItHasBeenCheckedError in Angular
published: true
description: 
tags: angular
canonical_url: https://indepth.dev/posts/1514/deep-dive-into-the-infamous-expressionchangedafterithasbeencheckederror-in-angular
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c42w1v04qdey8keufhma.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-01-31 07:30 +0000
---

# Overview

One of the most frequent Angular related topics on [StackOverflow](https://stackoverflow.com/questions/tagged/angular) is about the infamous [ExpressionChangedAfterItHasBeenCheckedError](https://github.com/angular/angular/blob/c5a84851ea20942c35b1c11ab0432f8ecd403043/packages/core/src/errors.ts#L23) error. Usually these questions come up because developers do not really understand why the check that produces this error is required. Many even view it as a flaw in the framework design. However, for Angular it’s simply a way to enforce [unidirectional data flow](/angular/big-picture/unidirectional-data-flow) and ensure that application state and UI are in sync after a single pass of change detection cycle.

Unidirectional data flow entails that once Angular has processed bindings for the current component, you can no longer update the properties of that component that make up bindings expressions. Angular implements [checkNoChanges](https://github.com/angular/angular/blob/a98fa489fb498273bdfde2fa4598893d1d53582e/packages/core/src/render3/view_ref.ts#L283) method that runs after a regular change detection cycle and re-evaluates binding expressions. If during this check Angular detects that an expression produces different value compared to the value it produced during the preceding [detectChanges](https://github.com/angular/angular/blob/a98fa489fb498273bdfde2fa4598893d1d53582e/packages/core/src/render3/view_ref.ts#L273) run, it will throw `ExpressionChangedAfterItHasBeenCheckedError`.

A binding defines the property name to update and the expression that produces a value for the property. Bindings are encoded as rendering engine (Ivy) [instructions](https://github.com/angular/angular/blob/99723fc64ed6ded3635ae5e19648550dc42f1bc1/packages/core/src/render3/instructions/all.ts#L28-L28) which Angular’s compiler puts into the component’s
[template function](/angular/big-picture/operations#template-function). When Angular checks a component view during change detection, it runs over all bindings by executing corresponding instructions. For each binding, it evaluates expressions and compares the results to the previous value produced by the expression. That’s where the name dirty checking comes from.

If those values differ, Angular updates the property defined by the binding. That’s what happens in the regular change detection cycle triggered by the `detectChanges` method. However, when running in special `checkNoChangesMode` that is triggered by `checkNoChanges` method, when the difference is detected, instead of updating the binding the `Expression Changed` error is thrown.

The function that checks for the difference and throws the error is [bindingUpdated](https://github.com/angular/angular/blob/663d477cb04da4960a9a6552c556abe73417b95b/packages/core/src/render3/bindings.ts#L46). Here’s a bit simplified implementation of this function:

```ts
export function bindingUpdated(lView, bindingIndex, value) {
  const oldValue = lView[bindingIndex];

  // no update is needed
  if (Object.is(oldValue, value)) {
    return false;
  } else {
    // if we're in development mode and the values are not equal,
    // throw the error and return without updating the binding
    if (ngDevMode && isInCheckNoChangesMode()) {
      const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined;
      if (!devModeEqual(oldValueToCompare, value)) {
        const details = getExpressionChangedErrorDetails(...);
        throwErrorIfNoChangesMode(oldValue === NO_CHANGE, details.oldValue, ...);
      }
      return false;
    }
    lView[bindingIndex] = value;
    return true;
  }
}
```

We can do a quick usage search to identify all Ivy instructions that use `bindingUpdated` and hence can throw the error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fkv4p7hyhgu4ngfxo10.png)

Interestingly, there’s also a [unit-test](https://github.com/angular/angular/blob/594bd12d5dba68b6073a4c42f0ccef2c6c8acb50/packages/core/test/acceptance/change_detection_spec.ts#L1353) that validates the logic that produces the error. Here’s how it checks if the [property](https://github.com/angular/angular/blob/d1ea1f4c7f3358b730b0d94e65b00bc28cae279c/packages/core/src/render3/instructions/property.ts#L35) instruction that updates the `[id]` property correctly throws the error:

```ts
class MyApp {
	  unstableStringExpression: string = 'initial';

	  ngAfterViewChecked() {
	    this.unstableStringExpression = 'changed';
	  }
}

it('should include field name in case of property binding', () => {
  const message = `Previous value for 'id': 'initial'. Current value: 'changed'`;
  expect(() => initWithTemplate('<div [id]="unstableStringExpression"></div>'))
      .toThrowError(new RegExp(message));
});
```

Test specs use `ngAfterViewChecked` lifecycle hook to update the property as this hook is triggered after the bindings have been processed. In the `it('should include field...)` spec we saw above, the setup starts with the value "initial" for the `unstableStringExpression` component property. Then inside the `ngAfterViewChecked` hook, the value is set to "changed". The `checkNoChanges` verification cycle will throw the `ExpressionChangedAfterItHasBeenCheckedError` error because it detects the difference.

**All this means that the root cause for the error is always the same - different value that comes to a binding during the regular `detectChanges` cycle and the validation `detectNoChanges` run. Accordingly, the primary fix is also always the same - ensuring the expression yields the same value during the regular `detectChanges` cycle and the verification `checkNoChanges` run.**

This test suit basically defines all possible cases when bindings will throw the error:

```ts
initWithTemplate('<div [id]="unstableStringExpression"></div>')
initWithTemplate('<div id="Expressions: {{ a }}')
initWithTemplate('<div [attr.id]="unstableStringExpression"></div>')
initWithTemplate('<div [style.color]="unstableColorExpression"></div>')
initWithTemplate('<div [class.someClass]="unstableBooleanExpression"></div>')
initWithTemplate('<div i18n>Expression: {{ unstableStringExpression }}</div>')
initWithTemplate('<div i18n-title title="Expression: {{ unstableStringExpression }}"></div>')
initWithHostBindings({'[id]': 'unstableStringExpression'})
initWithHostBindings({'[style.color]': 'unstableColorExpression'})
initWithHostBindings({'[class.someClass]': 'unstableBooleanExpression'})
```

The particular fix for the error depends on the leading cause
which is something that leads to the binding getting different values. To find the leading cause we need to know what binding gets different values and where the difference in values comes from. Usually finding this leading cause isn't straightforward and requires the use of lots of interesting debugging techniques to pinpoint the culprit and we’ll explore in-depth how to do that in the next section [finding the primary cause](https://courses.indepth.dev/angular/expression-changed-error/causes).

Let’s now take a look at a very simple illustration of this verification mechanism works.

### The error mechanism in details

To see how the error is detected and thrown we’ll implement a component that renders a random number obtained through `Math.random()`:

```ts
@Component({
  selector: 'p-cmp',
  template: `
    <h3>
      <button (click)="noop()">Generate number</button>
    </h3>
    <div [textContent]="number"></div>
  `
})
export class P {
  noop() {}
  get number() {
    return Math.random();
  }
}
```

The `number` expression used in the `[textContent]` binding gets different values during a regular and verification change detection cycles. Because of that fact, when we run the above application we can expect the error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6c453cctspfld39gr3m.png)

The leading cause here is that `Math.random()` produces different results each time it's called. So the value that `textContent` binding gets during the `detectChanges` will never match the value it receives for the `checkNoChanges` run.

The error we got gives us the following information:

> ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Previous value for 'textContent': '0.9449286101652989'. Current value: '0.1686897170657191'.
Find more at [https://angular.io/errors/NG0100](https://angular.io/errors/NG0100)

Just as we assumed, it tells us that the values produced by the expression `number` for the `textContent` binding were different during a regular change detection cycle and the verification run. This `textContent` binding is processed by the `property` instruction and we can see it in the callstack. The error itself comes from the `bindingUpdated` function we discussed above:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4m4ladzk28f6okbj123c.png)

We can even see it using Chrome dev tools:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgy072t1vi78yhs62l82.png)

That’s actually might be quite surprising to you because usually that error comes up in a lot more sophisticated scenarios. But can you think of a very trivial fix for this case? 🤓

This particular case actually matches this spec from above mentioned unit-test suite:

```ts
initWithTemplate('<div [id]="unstableStringExpression"></div>')
```

Of course, real world examples are much more intricate and complex. They usually involve a component hierarchy and an interaction mechanism between ancestors and their descendent components. This interaction is often indirect and happens through shared services, event emitters or observables. It takes good understand and lots of practice to quickly discover the leading cause.

To illustrate the error mechanism that involves a hierarchy, let’s look at the very basic setup with a parent and a child component.

### Updating ancestors

We’re defining a simple hierarchy of two components. A parent component declares the `text` property that is used in an interpolation binding. A child component injects the parent component through DI into the constructor and updates its `text` property in the `ngAfterViewChecked` hook. Just like Angular’s test suite, we use this hook because it’s triggered after the bindings have been processed.

Here’s the code snippet for the setup:

```ts
@Component({
  selector: 'q-cmp',
  template: `
    <h3>Q1 text: {{text}}</h3>
    <q1-cmp></q1-cmp>
  `
})
export class Q {
  text = 'initial';
}

@Component({
  selector: 'q1-cmp',
  template: ``
})
export class Q1 {
  constructor(private q: Q) {}

  ngAfterViewChecked() {
    this.q.text = 'updated';
  }
}
```

And as expected we get the error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpnwx63sp5envtp9zagg.png)

This time our demo setup corresponds to this spec from the unit tests suite:

```ts
initWithTemplate('<div id="Expressions: {{ a }}')
```

The relevant instruction is [interpolation](https://github.com/angular/angular/blob/d1ea1f4c7f3358b730b0d94e65b00bc28cae279c/packages/core/src/render3/instructions/text_interpolation.ts#L35) and we can see it in the callstack:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xe6dan7eejjj8np6xu8v.png)

Interestingly, sometimes we could even get the error if we update the property in the `ngOnInit` hook:

```ts
@Component({
  selector: 'q-cmp',
  template: `
    <q2-cmp></q2-cmp>
    <h3>Q2 text: {{text}}</h3>
  `
})
export class Q {
  text = 'initial';
}

@Component({
  selector: 'q2-cmp',
  template: ``
})
export class Q2 {
  constructor(private q: Q) {}

  ngOnInit() {
    this.q.text = 'updated';
  }
}
```

Here’s the error again:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnc7sngbqs3ul55n76f8.png)

What might be very surprising, but actually makes sense, is that the **error won’t happen if swap elements** in a template of the `Q` component from this:

```ts
<h3>Q2 text: {{text}}</h3>
<q2-cmp></q2-cmp>
```

to this:

```ts
<q2-cmp></q2-cmp>
<h3>Q2 text: {{text}}</h3>
```

Basically we’re placing `<q2-cmp>` before the interpolation update. Run the example, no error pops up.

The magic is in a template function that’s generated by the compiler. Here’s the order of instructions in the tempate function for the original order:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lppiikcz6c3dle5hcxja.png)

Compare it to the swapped elements setup:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z1w53eimjfs58wed2fo3.png)

You can see that when `<q2-cmp>` precedes the interpolation update `Q2 text: {{text}}`, the hook `ngOnInit` is executed from the template function `Q_Template` and **that happens before Angular updates the DOM**. That’s why there’s no error. However, if `<q2-cmp>` follows the interpolation update, the `ngOnInit` hook is executed through `executeInitAndCheckHooks` after the `text` property has been processed by the template function and hence the binding throws the error.