dotnet/aspnetcore · critical · InvalidOperationException

To support navigation locks, {GetType().Name} must override

Error message

To support navigation locks, {GetType().Name} must override {nameof(HandleLocationChangingHandlerException)}

What it means

The virtual HandleLocationChangingHandlerException throws InvalidOperationException by default. NavigationManager subclasses that enable navigation locks (RegisterLocationChangingHandler) must override this to decide how to surface handler exceptions, otherwise the lock machinery cannot function.

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 294cab2f9b)

Solutions

  1. Override protected override void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context) in your NavigationManager subclass (log, rethrow, or swallow per your policy).
  2. If you do not need locks, avoid calling RegisterLocationChangingHandler.
  3. Mirror the implementation in the framework's concrete NavigationManager (e.g. RemoteNavigationManager).

Example fix

// before
public class MyNavManager : NavigationManager { /* no override */ }

// after
public class MyNavManager : NavigationManager
{
    protected override void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context)
        => logger.LogError(ex, "Location changing handler failed for {Target}", context.TargetLocation);
}
Defensive patterns

Strategy: type-guard

Validate before calling

static bool SupportsNavigationLockExceptions(NavigationManager nm) =>
    nm.GetType().GetMethod("HandleLocationChangingHandlerException",
        BindingFlags.Instance | BindingFlags.NonPublic)?.DeclaringType != typeof(NavigationManager);

Type guard

static bool SupportsNavigationLocks(NavigationManager nm) =>
    nm.GetType().GetMethod("HandleLocationChangingHandlerException",
        System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)?.DeclaringType != typeof(NavigationManager)
    && nm.GetType().GetMethod("SetNavigationLockState",
        System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)?.DeclaringType != typeof(NavigationManager);

Try / catch

try { navManager.RegisterLocationChangingHandler(handler); }
catch (InvalidOperationException ex) when (ex.Message.Contains("HandleLocationChangingHandlerException"))
{ logger.LogError(ex, "NavigationManager does not support locks; skipping registration"); }

Prevention

When it happens

Trigger: RegisterLocationChangingHandler is used (activating the navigation-lock path) but the NavigationManager subclass did not override HandleLocationChangingHandlerException; a location-changing handler throws and the default virtual rethrows as InvalidOperationException.

Common situations: Custom NavigationManager in a nonstandard host enabling locks without completing the override contract; upgrading to a version that added navigation locks without updating the subclass.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/2d5c76545af24ad9. Report an issue: GitHub.