angular/angular · critical · RuntimeError

-209

-209

Error message

Unexpected type of the `APP_INITIALIZER` token value (expected an array, but got ${typeof this.appInits}). Please check that the `APP_INITIALIZER` token is configured as a `multi: true` provider.

What it means

ApplicationInitStatus injects APP_INITIALIZER with {optional: true} and expects an array, which is what a multi: true provider produces. In development mode its constructor verifies Array.isArray; providing the token without multi: true yields a single function (typeof 'function'), the array check fails, and RuntimeError -209 explains the misconfiguration.

Source

Thrown at packages/core/src/application/application_init.ts:228

export class ApplicationInitStatus {
  // Using non null assertion, these fields are defined below
  // within the `new Promise` callback (synchronously).
  private resolve!: (...args: any[]) => void;
  private reject!: (...args: any[]) => void;

  private initialized = false;
  public readonly done = false;
  public readonly donePromise: Promise<any> = new Promise((res, rej) => {
    this.resolve = res;
    this.reject = rej;
  });

  private readonly appInits = inject(APP_INITIALIZER, {optional: true}) ?? [];
  private readonly injector = inject(Injector);

  constructor() {
    if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
      throw new RuntimeError(
        RuntimeErrorCode.INVALID_MULTI_PROVIDER,
        'Unexpected type of the `APP_INITIALIZER` token value ' +
          `(expected an array, but got ${typeof this.appInits}). ` +
          'Please check that the `APP_INITIALIZER` token is configured as a ' +
          '`multi: true` provider.',
      );
    }
  }

  /** @internal */
  runInitializers() {
    if (this.initialized) {
      return;
    }

    const asyncInitPromises = [];
    for (const appInits of this.appInits) {
      const initResult = runInInjectionContext(this.injector, appInits);

View on GitHub (pinned to 51cb07e980)

Solutions

  1. Add multi: true to the APP_INITIALIZER provider entry.
  2. Register each initializer as its own provider entry, all with multi: true.
  3. Ensure the factory/value returns a function returning a Promise (or void); the multi flag is about the array, the return shape about awaiting.
  4. After fixing, restart ng serve / rebuild to re-run bootstrap.

Example fix

// before
providers: [
  {provide: APP_INITIALIZER, useFactory: () => initApp},
]

// after
providers: [
  {provide: APP_INITIALIZER, multi: true, useFactory: () => initApp},
]
Defensive patterns

Strategy: validation

Validate before calling

// Static check over provider arrays (dev tooling):
function assertAppInitializersMulti(providers: Provider[]): void {
  for (const p of providers) {
    if (p && typeof p === 'object' && 'provide' in p && (p as any).provide === APP_INITIALIZER) {
      if (!(p as any).multi) {
        throw new Error('APP_INITIALIZER must be registered with multi: true');
      }
    }
  }
}

Type guard

export function isMultiProvider(p: Provider): boolean {
  return typeof p === 'object' && p !== null && 'provide' in p &&
    (p as {multi?: boolean}).multi === true;
}

Prevention

When it happens

Trigger: Registering {provide: APP_INITIALIZER, useFactory: ...} (or useValue/useClass) without multi: true in any provider array of the bootstrapped app/platform. The check runs in the ApplicationInitStatus constructor during bootstrap, so the app fails at startup in dev mode.

Common situations: First-time APP_INITIALIZER usage forgetting multi: true; adding a second initializer and refactoring both into one non-multi provider; copy-pasted config from older docs; library configs (e.g. APP initialization in NgModules) missing the flag. Note the guard is dev-mode only, so production builds skip the explicit error but initialization still misbehaves.

Related errors


AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22). Data as JSON: /api/errors/e0194529a654f7de. Report an issue: GitHub.