dotnet/aspnetcore · error · Error
Renderer with ID ' ' is not listening for navigation events
Error message
Renderer with ID '${rendererId}' is not listening for navigation events What it means
Blazor's NavigationManager tracks per-renderer navigation callbacks in a map keyed by WebRendererId. setHasLocationChangingListeners is called by a renderer to toggle whether it has location-changing listeners; if no entry exists in navigationCallbacks for that rendererId it means the renderer never registered itself (via notifyLocationChanged / attachToEventDelegator path), so updating its listener flag is a programming error rather than a runtime condition.
Solutions
- Ensure Blazor has fully started (await Blazor.start) before invoking any navigation interop from .NET.
- Verify you are not mixing blazor.web.js and blazor.server.js / blazor.webassembly.js bundles on the same page.
- Confirm a single render mode is active and the renderer registered before any location-changing listener calls.
- Update all Blazor packages and the JS bundle to the same version.
Example fix
// before: calling navigation interop before start completes await Blazor.start(); // after: ensure the runtime signals readiness; do not call setHasLocationChangingListeners manually // (this is internal — only the framework should call it)
Defensive patterns
Strategy: validation
Validate before calling
// Do not invoke navigation interop until Blazor is ready
async function whenReady(): Promise<void> {
await (window as any).Blazor?.start?.();
}
await whenReady();
// then perform navigation calls from .NET Try / catch
try {
// navigation call
} catch (e) {
if (/not listening for navigation/i.test((e as Error).message)) {
await (window as any).Blazor.start();
// retry once
} else throw e;
} Prevention
- Await Blazor.start before any navigation interop.
- Use a single Blazor JS bundle per page (web.js, not server.js + webassembly.js).
- Keep a single active render mode to avoid renderer-ID mismatches.
- Align all Blazor package versions.
When it happens
Trigger: Thrown at line 69 when setHasLocationChangingListeners(rendererId, ...) is invoked but navigationCallbacks.get(rendererId) returns undefined. Happens if a renderer tries to set location-changing listeners before its callbacks were registered with the NavigationManager.
Common situations: Custom interop that calls Blazor navigation APIs out of order; a misconfigured multi-renderer setup; version skew where a renderer ID is passed that the JS runtime does not recognize; calling navigation interop before Blazor.start completes.
Related errors
- Interop methods are already registered for renderer
- Interop methods are not registered for renderer
- No interop methods are registered for renderer
- Could not find ' ' (' ' was undefined).
- Either assemblyName or dotNetObjectId must have a non null…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/c7349bbdafe74190.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Services/NavigationManager.ts:69
});
if (hasRegisteredNavigationEventListeners) {
return;
}
hasRegisteredNavigationEventListeners = true;
window.addEventListener('popstate', onPopState);
currentHistoryIndex = history.state?._index ?? 0;
attachEnhancedNavigationListener((internalDestinationHref, interceptedLink) => {
notifyLocationChanged(interceptedLink, internalDestinationHref);
});
}
function setHasLocationChangingListeners(rendererId: WebRendererId, hasListeners: boolean) {
const callbacks = navigationCallbacks.get(rendererId);
if (!callbacks) {
throw new Error(`Renderer with ID '${rendererId}' is not listening for navigation events`);
}
callbacks.hasLocationChangingEventListeners = hasListeners;
}
export function attachToEventDelegator(eventDelegator: EventDelegator): void {
// We need to respond to clicks on <a> elements *after* the EventDelegator has finished
// running its simulated bubbling process so that we can respect any preventDefault requests.
// So instead of registering our own native event, register using the EventDelegator.
eventDelegator.notifyAfterClick(event => {
if (!hasInteractiveRouter()) {
return;
}
handleClickForNavigationInterception(event, absoluteInternalHref => {
performInternalNavigation(absoluteInternalHref, /* interceptedLink */ true, /* replace */ false);
});
});View on GitHub (pinned to 3600ca084e)