dotnet/aspnetcore · error · InvalidOperationException
To support navigation locks
Error message
To support navigation locks, {GetType().Name} must override {nameof(HandleLocationChangingHandlerException)} What it means
Thrown by the default virtual HandleLocationChangingHandlerException when a registered location-changing handler throws a non-cancellation exception. The base NavigationManager refuses to silently swallow handler failures, so any subclass that opts into navigation locks (by calling RegisterLocationChangingHandler) must override this method to define its own error policy.
Solutions
- If you subclass NavigationManager, override HandleLocationChangingHandlerException (log, rethrow, or swallow per your error policy).
- Use the framework-provided managers (RemoteNavigationManager on Server, WebAssemblyNavigationManager on WASM) in app code - they already override this.
- In tests, derive from the framework manager or a testable base that overrides the lock methods, rather than the abstract base directly.
- Make your location-changing handlers exception-safe so the path that reaches this method is never hit.
Example fix
// before: custom NavigationManager subclass lacks the override
public class TestNavManager : NavigationManager { /* only Initialize */ }
// after: provide an error policy for handler exceptions
public class TestNavManager : NavigationManager
{
protected override void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context)
=> throw new InvalidOperationException("Navigation handler failed", ex);
} Defensive patterns
Strategy: validation
Validate before calling
var t = navManager.GetType();
var overriden = t.GetMethod(nameof(NavigationManager.HandleLocationChangingHandlerException), BindingFlags.Instance | BindingFlags.NonPublic)!.DeclaringType != typeof(NavigationManager);
if (!overriden) throw new InvalidOperationException($"{t.Name} cannot host navigation locks: override HandleLocationChangingHandlerException."); Try / catch
try { manager.RegisterLocationChangingHandler(handler); }
catch (InvalidOperationException ex) when (ex.Message.Contains("HandleLocationChangingHandlerException"))
{ /* swap in a manager that overrides the method, or drop the lock */ } Prevention
- Prefer the built-in Server/WebAssembly NavigationManager, which already override this.
- When subclassing NavigationManager for tests/hosting, override every lock-related virtual.
- Make NavigationLock handlers exception-safe so the path is never reached.
When it happens
Trigger: You call RegisterLocationChangingHandler (directly or via NavigationLock) on a NavigationManager whose concrete type has not overridden HandleLocationChangingHandlerException, and one of the registered handlers throws an exception that is not an OperationCanceledException. The framework's own Server/WebAssembly managers override it; custom test or mock subclasses typically do not.
Common situations: Writing a unit test or custom host that subclasses NavigationManager directly and exercises RegisterLocationChangingHandler; using a mock NavigationManager in tests without overriding the lock-support surface; a handler in a NavigationLock OnLocationChanging callback throws and the manager is a bare test double.
Related errors
- To support navigation locks
- An exception occurred while dispatching a location changed…
- ' ' has not been initialized.
- No component found for route
- Setting and properties simultaneously is not supported. Use…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/2d5c76545af24ad9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Components/src/NavigationManager.cs:560
await handler(context);
}
catch (OperationCanceledException)
{
// Ignore exceptions caused by cancellations.
}
catch (Exception ex)
{
HandleLocationChangingHandlerException(ex, context);
}
}
/// <summary>
/// Handles exceptions thrown in location changing handlers.
/// </summary>
/// <param name="ex">The exception to handle.</param>
/// <param name="context">The context passed to the handler.</param>
protected virtual void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context)
=> throw new InvalidOperationException($"To support navigation locks, {GetType().Name} must override {nameof(HandleLocationChangingHandlerException)}");
/// <summary>
/// Sets whether navigation is currently locked. If it is, then implementations should not update <see cref="Uri"/> and call
/// <see cref="NotifyLocationChanged(bool)"/> until they have first confirmed the navigation by calling
/// <see cref="NotifyLocationChangingAsync(string, string?, bool)"/>.
/// </summary>
/// <param name="value">Whether navigation is currently locked.</param>
protected virtual void SetNavigationLockState(bool value)
=> throw new NotSupportedException($"To support navigation locks, {GetType().Name} must override {nameof(SetNavigationLockState)}");
/// <summary>
/// Registers a handler to process incoming navigation events.
/// </summary>
/// <param name="locationChangingHandler">The handler to process incoming navigation events.</param>
/// <returns>An <see cref="IDisposable"/> that can be disposed to unregister the location changing handler.</returns>
public IDisposable RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask> locationChangingHandler)
{
AssertInitialized();View on GitHub (pinned to 3600ca084e)