Angular / Editorial solution guide

Resolve NG0203 outside an injection context

Identify where inject is called, capture the dependency during a supported context, and keep injector lifetime separate from asynchronous callback timing.

About 4 min readContent reviewed

Read-only knowledge base · No public comments

Recognize the symptoms

NG0203 reports that inject must be called from an injection context. It often appears after a call is moved into ngOnInit, a button handler, a utility callback, or code after await. The token may be provided correctly; this error concerns the missing current context, not necessarily the absence of a provider.

A direct new call in a test can reproduce a different construction path from Angular’s own DI creation. A class name or decorator does not make every later method invocation a context automatically. Preserve the stack and smallest calling path.

Understand the likely causes

  • Angular maintains a synchronous injection context during supported construction, field initialization, provider factories, and designated APIs. An ordinary later method is outside that context. runInInjectionContext establishes it for a given injector during its synchronous callback; the context does not automatically survive an asynchronous suspension.
  • A missing-provider error is another contract: a valid context still needs an injector that can resolve the actual token object. Adding a provider globally to solve NG0203 can change state scope while leaving the real timing defect. Identify context, token identity, provider location, and owner lifetime independently.

Locate the unsupported invocation

The contextual excerpt assumes a valid LABEL token but calls inject during an ordinary event handler. Angular creating the component earlier does not make this handler a construction context. It is marked non-runnable and no diagnostic reproduction is claimed from a browser fixture. Use the official NG0203 classification and the actual stack to find the late call rather than moving unrelated providers around.

typescript Contextual late injection call
onClick(): void {
  const label = inject(LABEL);
  console.log(label);
}

This method body requires its surrounding class and token. Calling it as an ordinary event handler has no automatic injection context; it is not executed here.

Capture once and use the dependency later

In a component, initialize a field with inject during Angular construction and use that field in the handler. For a utility deliberately supplied with an injector, run a synchronous context callback or use a supported explicit-injector API. The complete local example creates its own injector and captures a provided string before a later function uses it. This proves the selected context and lookup behavior without a browser. It does not prove that a destroyed service can remain safely usable after its owner ends.

typescript Complete isolated supported-context lookup
import { InjectionToken, Injector, inject, runInInjectionContext } from "@angular/core";
const LABEL = new InjectionToken<string>("label");
const owner = Injector.create({ providers: [{ provide: LABEL, useValue: "ready" }] });
const label = runInInjectionContext(owner, () => inject(LABEL));
function later(): string { return label.toUpperCase(); }
console.log(later());
owner.destroy();
Expected output
READY

The program prints READY before destroying its injector. It resolves one local value and starts no application or service.

Keep asynchronous work and scope honest

Do not place inject after await inside runInInjectionContext and assume the earlier stack frame still applies. Capture required dependencies before suspension, then manage their real lifetime through the owner. Keep a feature-scoped service feature-scoped unless the domain truly needs sharing; root provision is not a context repair. For takeUntilDestroyed outside implicit context, pass the captured DestroyRef explicitly. Test destruction with pending work so a timing repair does not create a resource leak or stale callback.

Verify the fix

Compile and run the complete isolated example with the pinned baseline and compare READY exactly. In the real component fixture, activate the handler after initialization and confirm the captured dependency belongs to the intended provider scope. Do not run the contextual invalid method as a standalone program.

Add tests for a child provider override, a missing token, and teardown where relevant. A successful lookup does not prove the correct instance lifetime. Record whether the test covered local DI, a component lifecycle, or browser interaction.

Keep it from recurring

  • Keep context-sensitive calls near supported initialization, export one token object, and document explicit injector ownership. Review callbacks and await boundaries when refactoring code that injects dependencies.

Official references