ionic-team/ionic-framework · critical · Error

Cannot activate an already activated outlet

Error message

Cannot activate an already activated outlet

What it means

Thrown by IonRouterOutlet.activateWith() when isActivated is already true. Angular's contract is that an outlet must be deactivated before it is reactivated; activateWith enforces this and fails fast on double-activation. This guards against corrupted navigation state where a new route is activated on top of an existing one without deactivation.

Source

Thrown at packages/angular/common/src/directives/navigation/router-outlet.ts:243

        this.activatedView.savedExtras = {};
        if (context.route) {
          const contextSnapshot = context.route.snapshot;

          this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams;
          (this.activatedView.savedExtras.fragment as string | null) = contextSnapshot.fragment;
        }
      }
      const c = this.component;
      this.activatedView = null;
      this.activated = null;
      this._activatedRoute = null;
      this.deactivateEvents.emit(c);
    }
  }

  activateWith(activatedRoute: ActivatedRoute, environmentInjector: EnvironmentInjector | null): void {
    if (this.isActivated) {
      throw new Error('Cannot activate an already activated outlet');
    }
    this._activatedRoute = activatedRoute;

    let cmpRef: any;
    let enteringView = this.stackCtrl.getExistingView(activatedRoute);
    if (enteringView) {
      cmpRef = this.activated = enteringView.ref;
      const saved = enteringView.savedData;
      if (saved) {
        // self-restore
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const context = this.getContext()!;
        context.children['contexts'] = saved;
      }
      // Updated activated route proxy for this component
      this.updateActivatedRouteProxy(cmpRef.instance, activatedRoute);
    } else {
      const snapshot = (activatedRoute as any)._futureSnapshot;

View on GitHub (pinned to 625f9c38ad)

Solutions

  1. Ensure versions of @ionic/angular and @angular/router are aligned per Ionic's compatibility matrix.
  2. Avoid triggering a second navigation while a page transition/activation is in flight (debounce or queue navigations).
  3. Check outlet.isActivated and let the standard router flow deactivate before reactivating; do not call activateWith directly.
  4. Simplify redirect/guard logic so it does not stack activations on the same outlet.

Example fix

// before
router.navigate(['/a']);
router.navigate(['/b']); // concurrent -> double activation possible

// after
await router.navigate(['/a']);
// transition complete, then
await router.navigate(['/b']);
Defensive patterns

Strategy: validation

Validate before calling

// Don't stack activations: let each navigation settle before the next.
await router.navigate(['/a']);
await router.navigate(['/b']);
// Also assert version compatibility at install time (peer deps).

Prevention

When it happens

Trigger: activateWith is called twice without an intervening deactivate(). This can happen with custom routers, mismatched Angular version internals, navigation triggered during an in-flight activation, or a guard/redirect that activates a second route while the first is still active.

Common situations: Angular version incompatibility (Ionic Angular vs @angular/router mismatch); redirect/guard logic that triggers concurrent navigations; manually calling router navigation inside a resolver; bugs from mixing NavController and Angular router.navigate in quick succession during transitions.

Related errors


AI-assisted analysis of ionic-team/ionic-framework@625f9c38ad (2026-08-12). Data as JSON: /api/errors/3afdf01052fd8655. Report an issue: GitHub.