{"record":{"id":"86efb65d6eba57a2","repo":"dotnet/aspnetcore","slug":"only-one-interactive-runtime-may-enable-navigation","errorCode":null,"errorMessage":"Only one interactive runtime may enable navigation interception at a time.","messagePattern":"Only one interactive runtime may enable navigation interception at a time\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/Components/Web.JS/src/Services/NavigationUtils.ts","lineNumber":154,"sourceCode":"      if (candidate instanceof HTMLAnchorElement || candidate instanceof SVGAElement) {\n        return candidate;\n      }\n    }\n  }\n  return null;\n}\n\nexport function hasInteractiveRouter(): boolean {\n  return interactiveRouterRendererId !== undefined;\n}\n\nexport function getInteractiveRouterRendererId() : WebRendererId | undefined {\n  return interactiveRouterRendererId;\n}\n\nexport function setHasInteractiveRouter(rendererId: WebRendererId) {\n  if (interactiveRouterRendererId !== undefined && interactiveRouterRendererId !== rendererId) {\n    throw new Error('Only one interactive runtime may enable navigation interception at a time.');\n  }\n\n  interactiveRouterRendererId = rendererId;\n}\n","sourceCodeStart":136,"sourceCodeEnd":159,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Services/NavigationUtils.ts#L136-L159","documentation":"Thrown by setHasInteractiveRouter() in NavigationUtils.ts:154 when a second interactive Blazor renderer tries to register as the navigation-intercepting router. Blazor's client-side navigation interception (click handling on anchors, popstate, etc.) can only be owned by a single interactive runtime, because two routers would race to interpret and handle the same navigation events. The guard compares the already-registered rendererId against the new one and throws if they differ.","triggerScenarios":"Calling setHasInteractiveRouter(rendererId) a second time with a different WebRendererId while a previous rendererId is already registered (interactiveRouterRendererId !== undefined && !=== rendererId). Happens when both InteractiveServer and InteractiveWebAssembly rendermodes initialize their routers in the same document.","commonSituations":"Blazor Web App with InteractiveAuto rendermode transitioning from Server to WebAssembly where both runtimes start and each calls setHasInteractiveRouter. Manually bootstrapping multiple Blazor runtimes on one page. Hot-reload or re-initialization during development that re-runs startup without the first runtime releasing control. Misconfigured custom hosting that loads two blazor.*.js runtimes.","solutions":["Ensure only one interactive runtime owns routing — for InteractiveAuto, the WebAssembly runtime should replace (not add to) the Server runtime; verify you are not double-registering both in production.","If you have a legitimate need for multiple runtimes, design only one of them to handle navigation and keep the others from calling setHasInteractiveRouter.","Check for accidental double script inclusion of blazor.web.js / blazor.webassembly.js in the host page.","On teardown or before re-init, call the equivalent reset path so interactiveRouterRendererId returns to undefined before a different renderer registers."],"exampleFix":"// before — both runtimes call this\nsetHasInteractiveRouter(WebRendererId.Server);\nsetHasInteractiveRouter(WebRendererId.WebAssembly); // throws\n\n// after — only the active router registers; the wasm runtime takes over after server relinquishes\nif (!hasInteractiveRouter()) {\n  setHasInteractiveRouter(currentRendererId);\n}","handlingStrategy":"validation","validationCode":"import { hasInteractiveRouter } from './NavigationUtils';\nfunction safeSetInteractiveRouter(id: WebRendererId) {\n  if (hasInteractiveRouter()) {\n    console.warn('Navigation interception already enabled; skipping re-registration.');\n    return;\n  }\n  setHasInteractiveRouter(id);\n}","typeGuard":"function canRegisterRouter(rendererId: WebRendererId): boolean {\n  return !hasInteractiveRouter();\n}","tryCatchPattern":null,"preventionTips":["Designate exactly one runtime as the navigation owner before booting any interactive runtime.","Guard setHasInteractiveRouter with hasInteractiveRouter() to avoid double registration.","Avoid loading both blazor.server.js and blazor.webassembly.js routers on a single page.","Reset the registered router on full teardown before re-initializing in development."],"tags":["blazor","navigation","router","rendermode","runtime-initialization"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}