TanStack/table · error

[@tanstack/angular-table] Cannot initialize object after vie

Error message

[@tanstack/angular-table] Cannot initialize object after view is destroyed

What it means

injectLazyInit creates a lazily initialized object tied to an Injector and DestroyRef. If the object was never initialized (still notInitializedObject) and the view is already destroyed, lazy initialization is impossible, so getObject throws this error instead of silently creating a leaked object.

Source

Thrown at packages/angular-table/src/injectLazyInit.ts:26

const notInitializedObject = Symbol('notInitializedObject')

export function injectLazyInit<T extends object>(
  initializer: () => T,
  cleanup: (object: T) => void,
): T {
  assertInInjectionContext(injectLazyInit)
  const destroyRef = injectCompatibleDestroyRef()
  let object: T | typeof notInitializedObject = notInitializedObject

  destroyRef.onDestroy(() => {
    if (object !== notInitializedObject) {
      cleanup(object)
    }
  })

  const getObject = () => {
    if (destroyRef.destroyed && object === notInitializedObject) {
      throw new Error(
        '[@tanstack/angular-table] Cannot initialize object after view is destroyed',
      )
    }
    if (object === notInitializedObject) {
      object = untracked(initializer)
    }
    return object
  }

  return new Proxy<T>({} as T, {
    get(_, prop, receiver) {
      return Reflect.get(getObject(), prop, receiver)
    },
    has(_, prop) {
      return Reflect.has(getObject(), prop)
    },
    ownKeys() {
      return Reflect.ownKeys(getObject())

View on GitHub (pinned to d01c01bedb)

Solutions

  1. Access/initialize the lazily created object while the view is alive (e.g. in the constructor, init, or an effect) so it exists before teardown
  2. Guard destroy-time reads with destroyRef.destroyed (or injector.get( DestroyRef).destroyed) before touching the object
  3. Unsubscribe from async callbacks on destroy so they never touch the object after the view is gone

Example fix

// before
ngOnDestroy() {
  this.table.rowSelection = {}; // first touch after destroy -> throws
}
// after
ngOnInit() {
  this.table = this.lazyTable; // force init while alive
}
ngOnDestroy() {
  if (this.destroyRef.destroyed) return;
  this.table.rowSelection = {};
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!this.destroyRef.destroyed) {
  this.table = this.lazyTable; // force init while alive
}

Type guard

function canAccessLazy(destroyRef: DestroyRef, initialized: boolean): boolean {
  return initialized || !destroyRef.destroyed;
}

Try / catch

try {
  doSomethingWith(lazyTableProxy);
} catch (e) {
  if (e.message.includes('after view is destroyed')) {
    // view already destroyed; skip
  } else { throw e; }
}

Prevention

When it happens

Trigger: Accessing a lazily initialized object (via get/has/ownKeys on the lazy proxy) after its DestroyRef has been destroyed and before it was ever initialized — e.g. reading a table instance in onDestroy/after destruction or in a detached callback.

Common situations: Cleanup/destroy hooks that touch the table instance for the first time; async callbacks resolving after the component view was destroyed (HTTP subscriptions, setTimeout); effects running during teardown.

Related errors


AI-assisted analysis of TanStack/table@d01c01bedb (2026-08-28). Data as JSON: /api/errors/2732c1fd04da3236. Report an issue: GitHub.