emberjs/ember.js · error · Error

Cannot call `.lookup('${fullName}')` after the owner has bee

Error message

Cannot call `.lookup('${fullName}')` after the owner has been destroyed

What it means

Container#lookup refuses to resolve any factory once the owner (application/instance) has been destroyed. Ember destroys owners during teardown (e.g. app.destroy() or test teardown); calling into a destroyed container is always a lifecycle bug, so it throws instead of returning stale objects.

Source

Thrown at packages/@ember/-internals/container/lib/container.ts:158

   let registry = new Registry();
   let container = registry.container();
    registry.register('api:twitter', Twitter);
    let twitter = container.lookup('api:twitter', { singleton: false });
   let twitter2 = container.lookup('api:twitter', { singleton: false });
    twitter === twitter2; //=> false
   ```
    @private
   @method lookup
   @param {String} fullName
   @param {RegisterOptions} [options]
   @return {any}
   */
  lookup(
    fullName: string,
    options?: RegisterOptions
  ): InternalFactory<object> | object | undefined {
    if (this.isDestroyed) {
      throw new Error(`Cannot call \`.lookup('${fullName}')\` after the owner has been destroyed`);
    }
    assert('fullName must be a proper full name', this.registry.isValidFullName(fullName));
    return lookup(this, this.registry.normalize(fullName), options);
  }

  /**
   A depth first traversal, destroying the container, its descendant containers and all
   their managed objects.
    @private
   @method destroy
   */
  destroy(): void {
    this.isDestroying = true;

    destroyDestroyables(this);
  }

  finalizeDestroy(): void {

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Ensure all async work referencing the owner completes or is cancelled before destroy()
  2. Re-check lifecycle: only call lookup while the app/instance is running
  3. Remove or tear down event listeners/timers in willDestroy
  4. In tests, await settled state before teardown (use ember-test-waiters / settled())

Example fix

// before
setTimeout(() => this.owner.lookup('service:session'), 5000);
// after
timer = setTimeout(() => {
  if (!this.isDestroying) this.owner.lookup('service:session');
}, 5000);
Defensive patterns

Strategy: validation

Validate before calling

if (owner.isDestroying || owner.isDestroyed) return; // skip lookup

Type guard

function isOwnerLive(owner) { return !owner.isDestroyed && !owner.isDestroying; }

Try / catch

try { return owner.lookup('service:foo'); } catch (e) { if (String(e.message).includes('after the owner has been destroyed')) return null; throw e; }

Prevention

When it happens

Trigger: Calling owner.lookup('service:foo') (directly or via controllerFor) after the owner's destroy() has run — e.g. in a setTimeout/async callback, an event listener not cleaned up, or code running after application.destroy().

Common situations: Tests hitting the error after teardown due to unresolved promises or lingering timers; app teardown while background jobs still call lookup; accessing a cached owner reference after restart in fastboot or engine teardown.

Related errors


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