dotnet/aspnetcore · critical · NotSupportedException

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

Error message

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

What it means

The virtual SetNavigationLockState throws NotSupportedException by default. When the first location-changing handler is registered, NavigationManager calls SetNavigationLockState(true) to enable interception; without an override the lock cannot be engaged.

Source

Thrown at src/Components/Components/src/NavigationManager.cs:569

        }
    }

    /// <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();

        var isFirstHandler = _locationChangingHandlers.Count == 0;

        _locationChangingHandlers.Add(locationChangingHandler);

        if (isFirstHandler)
        {
            SetNavigationLockState(true);
        }

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Override protected override void SetNavigationLockState(bool value) in your NavigationManager subclass to enable/disable interception with the host (e.g. JS interop call).
  2. Do not register location-changing handlers if your host does not support locks.
  3. Port the override from the framework's RemoteNavigationManager.

Example fix

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

// after
public class MyNavManager : NavigationManager
{
    protected override void SetNavigationLockState(bool value)
        => _jsRuntime.InvokeVoidAsync("myNav.setLock", value);
}
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

try { var sub = navManager.RegisterLocationChangingHandler(handler); }
catch (NotSupportedException ex) when (ex.Message.Contains("SetNavigationLockState"))
{ logger.LogWarning(ex, "Host NavigationManager lacks lock support"); }

Prevention

When it happens

Trigger: RegisterLocationChangingHandler is called on a NavigationManager subclass that did not override SetNavigationLockState; the first handler registration triggers the default virtual which throws.

Common situations: Custom host NavigationManager opting into navigation locks without implementing the lock-state hook; using NavigationLock component on a platform whose NavigationManager is incomplete.

Related errors


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