dotnet/aspnetcore · error · Error
Only one interactive runtime may enable navigation…
Error message
Only one interactive runtime may enable navigation interception at a time.
What it means
Blazor allows only one interactive runtime to own router-level navigation interception at a time. setHasInteractiveRouter stores the rendererId of that owner and refuses to overwrite it with a different rendererId. hasInteractiveRouter/getInteractiveRouterRendererId expose the current owner. This enforces a single source of truth for link-click interception when multiple renderers coexist.
Solutions
- Ensure only one interactive runtime registers as the interactive router on a page (typical: one render mode globally or per-page).
- Avoid loading both blazor.web.js and a second interactive host on the same page.
- Confirm you are not double-invoking Blazor.start or re-initializing the runtime.
- Align client and server Blazor versions so the renderer registration happens once.
Example fix
// before: two renderers both call setHasInteractiveRouter // after: only one interactive render mode per page // App.razor — pick ONE: <Routes @rendermode="InteractiveServer" /> <!-- or --> <Routes @rendermode="InteractiveWebAssembly" /> <!-- not both registered as routers simultaneously
Defensive patterns
Strategy: validation
Validate before calling
import { hasInteractiveRouter } from './NavigationUtils';
// before calling setHasInteractiveRouter
if (hasInteractiveRouter()) {
// another renderer already owns routing; do not register again
return;
} Try / catch
try {
setHasInteractiveRouter(rendererId);
} catch (e) {
if (/Only one interactive runtime/i.test((e as Error).message)) {
// pick one render mode; reload to reset
window.location.reload();
} else throw e;
} Prevention
- Run a single interactive render mode (Server OR WebAssembly OR Auto) per page.
- Do not load two Blazor JS hosts on the same page.
- Avoid double Blazor.start invocations.
- Keep server and client Blazor versions identical.
When it happens
Trigger: Thrown at line 154 when setHasInteractiveRouter(rendererId) is called with a rendererId different from the already-set interactiveRouterRendererId (which is not undefined). Happens when a second interactive runtime attempts to register as the router after a first one already did.
Common situations: Loading both a Server and a WebAssembly interactive renderer with their own routers on the same page; misconfigured Auto render mode spinning up two interactive runtimes that both try to own the router; double-Blazor.start; version skew causing duplicate renderer initialization.
Related errors
- The type does not implement .
- Cannot merge mismatching component descriptors
- Cannot supply a component of type
- ' ' already initialized.
- No component found for route
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/86efb65d6eba57a2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Services/NavigationUtils.ts:154
if (candidate instanceof HTMLAnchorElement || candidate instanceof SVGAElement) {
return candidate;
}
}
}
return null;
}
export function hasInteractiveRouter(): boolean {
return interactiveRouterRendererId !== undefined;
}
export function getInteractiveRouterRendererId() : WebRendererId | undefined {
return interactiveRouterRendererId;
}
export function setHasInteractiveRouter(rendererId: WebRendererId) {
if (interactiveRouterRendererId !== undefined && interactiveRouterRendererId !== rendererId) {
throw new Error('Only one interactive runtime may enable navigation interception at a time.');
}
interactiveRouterRendererId = rendererId;
}
View on GitHub (pinned to 3600ca084e)