angular/angular · error · DOMException

InvalidStateError

InvalidStateError

Error message

Cannot use precommitHandler when cancelable is 'false'

What it means

Calling event.intercept({precommitHandler: ...}) throws a DOMException with name 'InvalidStateError' when the NavigateEvent's cancelable flag is false. The precommit handler runs before commit and can cancel or redirect the navigation, which is only meaningful for cancelable navigations; non-cancelable navigations (as determined by who initiated them) reject this option per the spec step 'Cannot use precommitHandler when cancelable is false'.

Source

Thrown at packages/core/primitives/dom-navigation/testing/fake_navigation.ts:868

  event.sameDocument = sameDocument;

  let precommitHandlers: Array<(controller: NavigationPrecommitController) => Promise<void>> = [];
  let handlers: Array<() => PromiseLike<void> | void> = [];

  // https://whatpr.org/html/10919/nav-history-apis.html#dom-navigateevent-intercept
  event.intercept = function (
    this: InternalFakeNavigateEvent,
    options?: ExperimentalNavigationInterceptOptions,
  ): void {
    if (!this.canIntercept) {
      throw new DOMException(`Cannot intercept when canIntercept is 'false'`, 'SecurityError');
    }
    this.interceptionState = 'intercepted';
    event.sameDocument = true;
    const precommitHandler = options?.precommitHandler;
    if (precommitHandler) {
      if (!this.cancelable) {
        throw new DOMException(
          `Cannot use precommitHandler when cancelable is 'false'`,
          'InvalidStateError',
        );
      }
      precommitHandlers.push(precommitHandler);
    }
    if (event.interceptionState !== 'none' && event.interceptionState !== 'intercepted') {
      throw new Error('Event interceptionState should be "none" or "intercepted"');
    }
    event.interceptionState = 'intercepted';
    const handler = options?.handler;
    if (handler) {
      handlers.push(handler);
    }
    // override old options with new ones. UA _may_ report a console warning if new options differ from previous
    event.focusResetBehavior = options?.focusReset ?? event.focusResetBehavior;
    event.scrollBehavior = options?.scroll ?? event.scrollBehavior;
  };

View on GitHub (pinned to 51cb07e980)

Solutions

  1. Check event.cancelable before passing precommitHandler: e.intercept(e.cancelable ? {precommitHandler, handler} : {handler})
  2. Move logic that must always run into the regular `handler`, which is allowed for any intercepted navigation
  3. If the precommit behavior (cancel/redirect) is essential, initiate the navigation yourself via navigation.navigate() so the event is cancelable

Example fix

// before
event.intercept({
  precommitHandler: async (c) => { /* ... */ },
  handler: async () => { /* ... */ },
}); // InvalidStateError when cancelable === false

// after
event.intercept({
  precommitHandler: event.cancelable ? async (c) => { /* ... */ } : undefined,
  handler: async () => { /* ... */ },
});
Defensive patterns

Strategy: type-guard

Validate before calling

e.intercept({
  precommitHandler: e.cancelable ? myPrecommit : undefined,
  handler,
});

Type guard

const canPrecommit = (e: NavigateEvent): boolean => e.cancelable === true;

Try / catch

try {
  e.intercept({precommitHandler, handler});
} catch (err) {
  if (err instanceof DOMException && err.name === 'InvalidStateError') {
    e.intercept({handler}); // retry without the precommitHandler
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a precommitHandler (the experimental pre-commit interception option) to intercept() on a NavigateEvent where cancelable === false, e.g., navigations initiated by the user agent or explicitly non-cancelable navigate() calls.

Common situations: Using the experimental precommit/redirect Navigation API surface in a listener attached to all navigations; upgrading code that only used `handler` and assuming the new option is always accepted.

Related errors


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