keepcalculator

06 Numbers and Powers

Fix Angular NG0205 Injector Has Already Been Destroyed

Card No. 06·37733 · Updated · Standard formula, shown below

Angular’s NG0205 error, “Injector has already been destroyed,” typically appears when you try to use an injector or a service after the Angular application (or a specific part of it) has been torn down. This commonly happens with lazy-loaded modules, dynamic components, or long-lived subscriptions that aren’t cleaned up. This guide walks you through the most common causes and provides practical fixes to resolve the error in your Angular application.

What You’ll Need

  • An Angular project where the error occurs (Angular 12+ recommended for the most relevant behavior).
  • Basic familiarity with Angular dependency injection, services, and lifecycle hooks.
  • Access to your code editor and browser developer tools (console).

Step-by-Step

  1. Reproduce the error and capture the stack trace.

    Open your browser’s developer console and trigger the action that causes the error. Note the full stack trace—it will point to the exact line where you’re using the destroyed injector. This is your starting clue.

  2. Identify where you’re using the injector after destruction.

    Common places: inside setTimeout, setInterval, RxJS subscriptions, promises, or event handlers that fire after the component or module is destroyed. Look for any code that calls inject(), uses a constructor-injected service, or accesses Injector directly in a callback.

  3. Check for lazy-loaded modules or dynamically created components.

    If the error occurs when navigating away from a lazy-loaded route or after destroying a dynamically created component, the injector for that module/component is being destroyed while something still holds a reference to it. Ensure you don’t store injectors or services in global singletons (like a service provided in root) that outlive the module.

  4. Fix subscriptions and timers in components.

    In every component that subscribes to an observable or uses a timer, implement OnDestroy and unsubscribe. Use the AsyncPipe where possible—it handles unsubscription automatically. For manual subscriptions, store them and call unsubscribe() in ngOnDestroy().

    export class MyComponent implements OnDestroy {
      private sub: Subscription;
    
      ngOnInit() {
        this.sub = someService.data$.subscribe(...);
      }
    
      ngOnDestroy() {
        this.sub?.unsubscribe();
      }
    }
  5. Use takeUntilDestroyed (Angular 16+) or a subject-based pattern.

    For Angular 16 and later, use the takeUntilDestroyed operator in components. For older versions, create a Subject<void> that you complete in ngOnDestroy and use with takeUntil.

    private destroy$ = new Subject();
    
    ngOnInit() {
      someService.data$.pipe(takeUntil(this.destroy$)).subscribe(...);
    }
    
    ngOnDestroy() {
      this.destroy$.next();
      this.destroy$.complete();
    }
  6. Avoid calling inject() inside callbacks or async contexts.

    The inject() function only works within the synchronous injection context (like a constructor or a factory). If you call it inside a setTimeout or a promise callback, it will throw this error. Instead, capture the injector or the needed service in the synchronous context and use that reference.

  7. For dynamic components, use ComponentRef properly.

    If you create a component with ComponentFactoryResolver or ViewContainerRef.createComponent, make sure you destroy it when the parent is destroyed. Call componentRef.destroy() in the parent’s ngOnDestroy or use the @if control flow (Angular 17+) which handles destruction automatically.

  8. Check for services that use providedIn: 'any' or are provided in a lazy module.

    If a service is provided in a lazy-loaded module, it gets its own child injector. When the module is unloaded, that injector is destroyed. If you inject that service into a singleton (provided in root), you’ll get a reference to a destroyed injector. Move the service to providedIn: 'root' if it doesn’t need module-specific state, or restructure your code to avoid cross-injector references.

  9. Use EnvironmentInjector for long-lived operations.

    If you need to create components or run code after a module is destroyed (e.g., for a background task), use the EnvironmentInjector from the root application instead of the module’s injector. Inject EnvironmentInjector in your service and use it to create components or run code that needs DI.

  10. Test your fix.

    After applying the changes, navigate through the app, especially the routes/actions that previously triggered the error. Check the console to confirm the error is gone. Also run your unit tests to ensure nothing broke.

Common Mistakes

  • Forgetting to unsubscribe from long-lived observables like route.params, form.valueChanges, or services that emit continuously.
  • Using inject() inside a callback—it’s not allowed outside the injection context.
  • Storing an injector reference in a global variable (e.g., a service provided in root) and using it later after the module is destroyed.
  • Not destroying dynamic components—leaving them attached to the view after the parent is destroyed.
  • Assuming take(1) or first() is enough—if the observable never emits, the subscription stays active.

Tips

  • Use the AsyncPipe in templates for observables—Angular handles unsubscription automatically.
  • Enable Angular’s strict mode in tsconfig.json to catch potential lifecycle issues at compile time.
  • Use the Angular DevTools profiler to see when modules are destroyed and what might be holding references.
  • For Angular 16+, prefer takeUntilDestroyed—it’s cleaner and less error-prone.
  • If you’re using a shared service to communicate between components, consider using a BehaviorSubject and completing it in the service’s own ngOnDestroy (if the service is provided in a component).

Troubleshooting

If the error persists after following the steps:

  • Check if the error occurs only in development or also in production. Sometimes HMR (Hot Module Replacement) can cause false positives; a full page reload might clear it.
  • Search your codebase for direct Injector usage. Look for Injector.create() or injector.get() calls outside of the injection context.
  • Examine the stack trace more closely. It often shows the exact line where the destroyed injector is accessed. Put a breakpoint there and inspect the injector’s state.
  • Check if you’re using a third-party library that might be holding onto an injector. Look for known issues with that library and Angular versions.
  • Try updating Angular to the latest patch version. The error might be a bug that’s already fixed.
  • If all else fails, create a minimal reproduction and isolate the problematic code. Sometimes the issue is a combination of factors that only appear in a specific context.

Frequently Asked Questions

Why does this error happen only when navigating away from a route?

When you navigate away, Angular destroys the component and its injector. If you have a subscription or timer that tries to use that injector after navigation, you get the error. The fix is to clean up those resources in ngOnDestroy.

Can I catch this error and ignore it?

You can wrap the code in a try/catch, but it’s not recommended. The error indicates a memory leak or a design flaw. Ignoring it will lead to unpredictable behavior and performance issues. Fix the root cause instead.

Does this error occur in Angular 17 or 18?

Yes, it can occur in any version. However, Angular 16+ provides takeUntilDestroyed which makes it easier to avoid. The underlying cause is the same.

Is it safe to use providedIn: 'root' for all services?

Generally yes, but if a service holds state that should be scoped to a module, using root might cause memory leaks or shared state across modules. Use root for stateless or truly global services.

What is the difference between Injector and EnvironmentInjector?

Injector is the base class; EnvironmentInjector is a specific type that represents the injector for an environment (like a module or the root). Using EnvironmentInjector from the root can help avoid the destroyed injector issue because it’s tied to the application’s lifetime, not a module’s.

Can this error be caused by Angular’s change detection?

Indirectly, yes. If you trigger change detection after a component is destroyed (e.g., via ApplicationRef.tick()), it might try to access a destroyed injector. Use ChangeDetectorRef carefully and check destroyed property if available.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →