angular/angular-cli · warning

[NG HMR] Cannot get 'PlatformRef'.

Error message

[NG HMR] Cannot get 'PlatformRef'.

What it means

A console.warn from the Angular CLI HMR helper after a hot update. The helper locates the application root element and asks ng.getInjector(appRoot).get(PlatformRef) so it can destroy the old platform before re-bootstrapping. When PlatformRef cannot be resolved from that injector, the warning fires, the old platform is left undestroyed, and the HMR state-restore flow is skipped.

Source

Thrown at packages/angular_devkit/build_angular/src/tools/webpack/plugins/hmr/hmr-accept.ts:155

function getToken<T>(appRoot: any, token: Type<T>): T | undefined {
  return (typeof ng === 'object' && ng.getInjector(appRoot).get(token)) || undefined;
}

function getApplicationRef(appRoot: any): ApplicationRef | undefined {
  const appRef = getToken(appRoot, ApplicationRef);
  if (!appRef) {
    console.warn(`[NG HMR] Cannot get 'ApplicationRef'.`);

    return undefined;
  }

  return appRef;
}

function getPlatformRef(appRoot: any): PlatformRef | undefined {
  const platformRef = getToken(appRoot, PlatformRef);
  if (!platformRef) {
    console.warn(`[NG HMR] Cannot get 'PlatformRef'.`);

    return undefined;
  }

  return platformRef;
}

function dispatchEvents(element: any): void {
  element.dispatchEvent(
    new Event('input', {
      bubbles: true,
      cancelable: true,
    }),
  );

  element.blur();

  element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Make sure only one Angular platform instance/bootstrapped root exists on the page (guard bootstrapModule with an already-bootstrapped check).
  2. Disable scripts optimization in dev so the ng global matches the bundled Angular core (angular.json development: optimization.scripts = false).
  3. Deduplicate @angular/core across bundle and dependencies so the token instance matches.
  4. Disable HMR (--no-hmr) if the app uses a non-standard bootstrap that HMR cannot handle.

Example fix

// main.ts — before
platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
// after (idempotent re-bootstrap, HMR-friendly)
if (!window['ng']) { platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err)); }
Defensive patterns

Strategy: validation

Validate before calling

const appRoot = document.querySelector('[ng-version]');
if (!appRoot || !(window as any).ng?.getInjector?.(appRoot)?.get) {
  console.warn('[NG HMR] Platform injector not resolvable; HMR will skip re-bootstrap.');
}

Type guard

function hasPlatformInjector(ng: any, appRoot: Element): boolean {
  try { return !!ng?.getInjector?.(appRoot)?.get; } catch { return false; }
}

Prevention

When it happens

Trigger: During the mod.hot.dispose callback: getToken(appRoot, PlatformRef) returns undefined because the injector found on the [ng-version] element is not the root platform injector (wrong element matched), ng.getInjector is present but stale (old destroyed app), or a single Angular core instance is not shared between the bundle and the HMR runtime.

Common situations: Multiple Angular apps or a re-bootstrap on the same page leaving a stale [ng-version] element; zoneless/experimental bootstrap setups where injector resolution differs; bundled runtime where ng global points to a different Angular core copy than the app's; scripts optimization partially enabled.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/524a63ce654ccec2. Report an issue: GitHub.