emberjs/ember.js · error · Error

You can't call rerender on a view being destroyed

Error message

You can't call rerender on a view being destroyed

What it means

Ember view lifecycle states enforce which operations are legal on a view. When a view has entered the 'destroying' state, calling rerender() is forbidden because the view's renderer and DOM context are being torn down. The states machine in states.ts throws this Error to prevent re-render work on a dead view.

Source

Thrown at packages/@ember/-internals/views/lib/views/states.ts:105

        set(value) {
          if (value !== elementId) {
            throw new Error("Changing a view's elementId after creation is not allowed");
          }
        },
      });
    }
  },
});

const DESTROYING: Readonly<ViewState> = Object.freeze({
  ...DEFAULT,

  appendChild() {
    throw new Error("You can't call appendChild on a view being destroyed");
  },

  rerender() {
    throw new Error("You can't call rerender on a view being destroyed");
  },
});

/*
  Describe how the specified actions should behave in the various
  states that a view can exist in. Possible states:

  * preRender: when a view is first instantiated, and after its
    element was destroyed, it is in the preRender state
  * hasElement: the DOM representation of the view is created,
    and is ready to be inserted
  * inDOM: once a view has been inserted into the DOM it is in
    the inDOM state. A view spends the vast majority of its
    existence in this state.
  * destroyed: once a view has been destroyed (using the destroy
    method), it is in this state. No further actions can be invoked
    on a destroyed view.
*/

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Guard rerender calls with an isDestroying/isDestroyed check
  2. Cancel async work in willDestroy (cancel timers, resolve/abort promises)
  3. Use @ember/runloop schedule/cancel so pending work is cancelled on teardown
  4. Remove event listeners and observers on destroy

Example fix

// before
didReceiveAttrs() {
  fetch('/data').then(() => this.rerender());
}
// after
didReceiveAttrs() {
  fetch('/data').then(() => {
    if (!this.isDestroying && !this.isDestroyed) this.rerender();
  });
}
Defensive patterns

Strategy: validation

Validate before calling

if (!view.isDestroying && !view.isDestroyed) { view.rerender(); }

Type guard

function canRerender(view) { return view && !view.isDestroying && !view.isDestroyed; }

Try / catch

try { view.rerender(); } catch (e) { if (!/being destroyed/.test(e.message)) throw e; /* ignore teardown race */ }

Prevention

When it happens

Trigger: Calling view.rerender() after the view has begun destruction — e.g. during willDestroyElement, willDestroy, or from a component triggered asynchronously (timer, promise) that resolves after the component is being destroyed.

Common situations: Async callbacks (setTimeout, debounce, promise resolution, event listeners) firing while a component unmounts during route transition; tests that tear down the app while rerender is queued.

Related errors


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/7ed5ccb1703bead4. Report an issue: GitHub.