NG0203 は、inject() を「注入コンテキスト(injection context:Angular が部品を作っている最中の、inject() が使える時間と場所)」の外で呼んだときのエラーです。 inject() は、クラスを作るその瞬間にだけ使えます。メソッドの中や、setTimeout・await の後のように「作り終わった後」に呼ぶと、このエラーになります。

v22.2.2 で、クリック時に呼ばれるメソッドの中で inject() したときの文面です。

ERROR RuntimeError: NG0203: The `_Api45` token injection failed. `inject()` function must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://v22.angular.dev/errors/NG0203

直し方の基本は、inject() をフィールド初期化子(クラスのフィールドに書く初期値)か constructor に移し、受け取ったものをメソッドで使うことです。

@Component({ selector: 'app-items', template: `<button (click)="load()">読み込む</button>` })
export class Items {
  private api = inject(Api);          // ← ここで受け取る(フィールド初期化子)

  load() {
    this.api.get(1);                  // ← メソッドでは受け取ったものを使う
    // inject(Api).get(1);            // ✕ NG0203
  }
}

起きる場所と直し方を並べると、次のとおりです。いずれも v22.2.2 で再現した結果です。

呼んだ場所 結果 直し方
フィールド初期化子・constructor 使える —
メソッド(クリック時など) NG0203 フィールドで受け取っておく
ngOnInit などのライフサイクル NG0203 フィールドで受け取っておく
setTimeout・await の後 NG0203 先に受け取っておく
関数ガードの await の後 NG0203 await の前に全部受け取る
ngOnInit での toSignal・effect・takeUntilDestroyed NG0203 フィールドで書く/injector・DestroyRef を渡す
テストの it() の中 NG0203 TestBed.inject()・TestBed.runInInjectionContext()

確認環境:Angular 22.2.2(@angular/core・@angular/router・@angular/cli)、TypeScript 6.0.3、Node.js 24.21.0(Linux)。ng new のプロジェクトで、TestBed+Vitest 5.0.4 と、ng build した画面を Chromium(Playwright)で開いて再現しました。v16・v19〜v21 の文面は、npm の @angular/core 16.2.12・19.2.25・20.3.33・21.2.25 の配布コードで確かめました(確認日 2026年10月12日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「NG0203の直し方|inject()とinjection context」

エラー文の読み方

v22.2.2 の文面は、inject() を直接呼んだときと、toSignal() などの関数の中で起きたときで、書き出しが違いました。

書き出し 何が起きたか
The `_Api` token injection failed. `inject()` function must be called … inject(Api) を外で呼んだ。_Api が受け取ろうとしたもの
The `Router` token injection failed. … inject(Router) を外で呼んだ(ガードの await の後など)
toSignal() can only be used within an injection context … toSignal() を外で呼んだ
takeUntilDestroyed() can only be used within … 引数なしの takeUntilDestroyed() を外で呼んだ
effect() can only be used within … effect() を外で呼んだ
injectApi() can only be used within … 自作関数の assertInInjectionContext(injectApi) で検出した

_Api の先頭の _ は、開発ビルドでクラス名に付いたもので、ソースでは Api です。token injection failed の前の名前で、どの inject() かが分かります。 can only be used の形なら、その関数を呼んだ場所を探します。

版による文面の違い

版 文面の書き出し
v16.2.12 NG0203: inject() must be called from an injection context such as a constructor, …
v19.2.25〜v22.2.2 NG0203: The `X` token injection failed. `inject()` function must be called from an injection context …

検索でよく見る inject() must be called from an injection context は、以前の文面です。番号の NG0203 は同じなので、番号で探すと同じエラーの情報に当たります。

本番ビルドでは名前が出ない

同じ画面を本番ビルド(ng build の既定)で開くと、次だけが出ました。

ERROR y: NG0203
    at Bb (http://localhost:4402/main-HMJZD2CD.js:4:2290)

どの inject() かを調べるときは、開発ビルド(ng serve)で同じ操作をします。

注入コンテキストとは

angular.dev では、注入コンテキストを次のように説明しています。

注入コンテキストになる場所 例
DI が作るクラスの constructor の中 @Component・@Injectable の constructor
そのクラスのフィールド初期化子 private api = inject(Api);
useFactory の関数 { provide: X, useFactory: () => new X(inject(Y)) }
InjectionToken の factory new InjectionToken('T', { factory: () => inject(Y) })
注入コンテキストで動く関数の中 ガード・リゾルバー・インターセプター・runInInjectionContext

大事なのは「どこに書いたか」ではなく「いつ実行されたか」です。 constructor の中に書いた処理でも、setTimeout や await の後に動く部分は、constructor が終わった後に実行されるので外になります。

場所別:再現したコードとエラー

① メソッドの中

load() { return inject(Api).get(1); }      // クリックなどで呼ばれる

冒頭のエラーが出ました。フィールドで受け取ります。

② ngOnInit などのライフサイクル

export class InOnInit implements OnInit {
  api?: Api;
  ngOnInit() { this.api = inject(Api); }   // ✕
}
NG0203: The `_Api` token injection failed. `inject()` function must be called from an injection context …

angular.dev でも、ライフサイクルフックの中は「インスタンスができた後なので遅すぎる」と説明されています。ngOnInit で使いたいものも、フィールドで受け取っておきます。ライフサイクルの順番は関連記事「Angularライフサイクル一覧|ngOnInitなどの実行順をログで確認」で扱っています。

③ setTimeout・Promise・await の後

constructor() {
  setTimeout(() => inject(Api));          // ✕ constructor が終わった後に動く
  this.init();
}
private async init() {
  await Promise.resolve();
  inject(Api);                            // ✕ await の後
}

どちらも同じ NG0203 になりました。await の前(同期で動く部分)なら使えます。 先に受け取り、後で使います。

private api = inject(Api);
private async init() {
  await Promise.resolve();
  this.api.get(1);                        // ○
}

④ 関数ガード・リゾルバーの await の後

ガードやリゾルバーの関数は、注入コンテキストの中で呼ばれます。ただし、最初の await までです。

// ✕ await の後で inject(Router)
export const badGuard: CanActivateFn = async () => {
  const ok = await inject(Auth).check();          // ここまでは使える
  return ok ? true : inject(Router).parseUrl('/login');   // ✕
};
NG0203: The `Router` token injection failed. `inject()` function must be called from an injection context …
// ○ 先に全部受け取る
export const authGuard: CanActivateFn = async () => {
  const auth = inject(Auth);
  const router = inject(Router);
  const ok = await auth.check();
  return ok ? true : router.parseUrl('/login');
};

直した形では、/good への遷移が通りました。Observable の pipe() の中も、値が後から届く場合(HTTP の応答など)は外になります。同期で値が流れる of(1).pipe(switchMap(…)) の中では使えましたが、これは動いた時点がたまたま中だっただけです。ガードの全体は関連記事「Angularガードの使い方|CanActivateFnでログインリダイレクト」で扱っています。

⑤ toSignal・effect・takeUntilDestroyed を ngOnInit で使う

ngOnInit() {
  this.s = toSignal(of(1));                                   // ✕
  effect(() => this.n());                                     // ✕
  interval(1000).pipe(takeUntilDestroyed()).subscribe();      // ✕
}
NG0203: toSignal() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`.
NG0203: effect() can only be used within an injection context …
NG0203: takeUntilDestroyed() can only be used within an injection context …

これらの関数は、中で inject() を使っています(破棄のタイミングを知るため)。直し方は2つあります。

export class Fixed implements OnInit {
  // 直し方1:フィールドに書く
  value = toSignal(this.api.items$);

  private injector = inject(Injector);
  private destroyRef = inject(DestroyRef);

  ngOnInit() {
    // 直し方2:injector・DestroyRef を渡す
    const s = toSignal(of(5), { injector: this.injector, requireSync: true });
    effect(() => console.log(s()), { injector: this.injector });
    interval(1000).pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
  }
}

2 の形で、3つともエラーなく動きました(toSignal は 5 を返しました)。toSignal の使い方は関連記事「Angular RxJS と Signals の使い分け|toSignal判断フロー」、購読の解除は関連記事「Angular unsubscribeの方法5つと要否早見表」で扱っています。

直し方の一覧

直し方 使う場面 コード
フィールド初期化子 ほとんどの場合(第一候補) private api = inject(Api);
constructor 受け取った値で初期化もしたい constructor() { this.api = inject(Api); }
runInInjectionContext 後から inject() を使う関数を呼びたい runInInjectionContext(this.injector, () => …)
injector を渡す toSignal・effect・afterNextRender など { injector: this.injector }
DestroyRef を渡す takeUntilDestroyed takeUntilDestroyed(this.destroyRef)
assertInInjectionContext 自作の injectXxx() 関数 外で呼ばれたら分かるエラーにする

runInInjectionContext:後から注入コンテキストで動かす

import { Component, Injector, inject, runInInjectionContext } from '@angular/core';

export class Report {
  private injector = inject(Injector);   // 先に Injector を受け取っておく

  onClick() {
    runInInjectionContext(this.injector, () => {
      const api = inject(Api);           // ここでは使える
      api.get(4);
    });
  }
}

runInInjectionContext(injector, fn) は、fn を、渡した injector の注入コンテキストで動かします。v22.2.2 で ngOnInit から呼んでも、中の inject(Api) が動きました。ただし、fn を async にして await した後は、やはり NG0203 になりました。 inject() を使いたい関数を、あとから呼ぶ場面(inject() 前提のライブラリ関数を、イベントの中で呼ぶなど)に使います。フィールドで受け取れるなら、そのほうがコードは短くなります。

assertInInjectionContext:自作関数で早めに分かるようにする

inject() を中で使う関数を自分で作るときは、先頭で assertInInjectionContext を呼んでおくと、外で呼ばれたときのエラーに関数名が出ます。

import { assertInInjectionContext, inject } from '@angular/core';

export function injectApi() {
  assertInInjectionContext(injectApi);   // 自分自身を渡す
  return inject(Api);
}
NG0203: injectApi() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`.

token injection failed の文面より、どの関数を呼んだ場所が悪いのかが分かりやすくなります。

テストで出るとき

テストの it() の中で inject(Api) を直接呼ぶと、NG0203 になりました。テストでは次の2つを使います。

it('Api を使う', () => {
  const api = TestBed.inject(Api);                       // ○ item9
  TestBed.runInInjectionContext(() => {
    const api2 = inject(Api);                            // ○ item10
  });
});

TestBed.runInInjectionContext は、inject() を中で使う関数(関数ガードや injectApi() など)を、テストから直接呼ぶときに使えます。テストの書き方は関連記事「Angular テスト Vitest 入門|v22の書き方・移行・実行結果つき」で扱っています。

NullInjectorError(NG0201)との違い

エラー 意味 見るところ
NG0203 inject() を呼んだ「時と場所」が外 どこで・いつ inject() しているか
NG0201 呼んだ場所は正しいが、提供元が無い providers・providedIn

NG0201 は関連記事「NullInjectorError No provider forの直し方|原因一覧」で扱っています。inject() と constructor 引数の違いは、関連記事「Angularサービスと依存性注入|injectとconstructorの違い」で扱っています。

よくある質問

Q. constructor に書いたのにエラーになります。 A. その inject() が、subscribe のコールバック・setTimeout・then・await の後にないかを見ます。constructor の中に書いても、後で動く部分は外になります。

Q. サービスのメソッドの中で inject() してもいいですか。 A. サービスでもコンポーネントと同じく、メソッドの中は外になり、providedIn: 'root' のサービスのメソッドで inject() すると NG0203 になりました。サービスもフィールド初期化子で受け取ります。

Q. インターセプターで inject() は使えますか。 A. 関数型のインターセプター(HttpInterceptorFn)は、注入コンテキストで呼ばれます。関数の先頭の inject() は動きましたが、next(req).pipe(tap(() => inject(Api))) のように応答の後で動く部分では NG0203 になりました。関数の先頭で受け取ります。インターセプターは関連記事「Angularインターセプターの使い方|トークン付与とエラー共通処理」で扱っています。

Q. ライブラリの関数(injectXxx() など)で NG0203 が出ます。 A. その関数が中で inject() を使っています。自分のコードと同じく、フィールド初期化子か constructor で呼びます。

まとめ

  • NG0203 は、inject() を作り終わった後に呼んだときのエラー。書いた場所より「いつ動いたか」で決まる
  • 第一候補の直し方は フィールド初期化子で受け取り、メソッドで使う
  • await・setTimeout・subscribe の後は外。ガード・リゾルバーでも最初の await の前に全部受け取る
  • toSignal・effect・takeUntilDestroyed は、フィールドに書くか injector・DestroyRef を渡す
  • 後から動かすなら runInInjectionContext、自作関数には assertInInjectionContext、テストは TestBed.inject

参考・出典

確認日はいずれも 2026年10月12日です。

  • Angular「NG0203: inject() must be called from an injection context」:https://angular.dev/errors/NG0203
  • Angular「Injection context」:https://angular.dev/guide/di/dependency-injection-context
  • Angular「runInInjectionContext」:https://angular.dev/api/core/runInInjectionContext
  • Angular「assertInInjectionContext」:https://angular.dev/api/core/assertInInjectionContext
  • Angular「toSignal」:https://angular.dev/api/core/rxjs-interop/toSignal

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「NG0203の直し方|inject()とinjection context」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?