dotnet/aspnetcore · error · NotSupportedException

To support navigation locks

Error message

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

What it means

Thrown by the default virtual SetNavigationLockState when the first location-changing handler is registered. NavigationLock support requires the host to physically suppress URI changes until NotifyLocationChangingAsync confirms them; the base class cannot do that, so it demands an override. Without the override, registering a NavigationLock would silently no-op and break the contract.

Solutions

  1. Override SetNavigationLockState(bool) in your NavigationManager subclass to actually enable/disable interception in your host.
  2. Use the built-in Server/WebAssembly NavigationManager implementations, which already override it.
  3. Do not call RegisterLocationChangingHandler (or render a NavigationLock component) against a manager that does not support locks.
  4. In tests, use the framework test double (e.g. FakeNavigationManager or a derived RemoteNavigationManager) that supplies the overrides.

Example fix

// before: subclass missing the override, registering a lock throws
public class CustomNavManager : NavigationManager { }
// _ = manager.RegisterLocationChangingHandler(...); // throws

// after: override so the host honors the lock flag
public class CustomNavManager : NavigationManager
{
    private bool _locked;
    protected override void SetNavigationLockState(bool value) => _locked = value;
}
Defensive patterns

Strategy: validation

Validate before calling

var t = navManager.GetType();
var overriden = t.GetMethod(nameof(NavigationManager.SetNavigationLockState), BindingFlags.Instance | BindingFlags.NonPublic)!.DeclaringType != typeof(NavigationManager);
if (!overriden) throw new NotSupportedException($"{t.Name} cannot host navigation locks: override SetNavigationLockState.");

Try / catch

try { manager.RegisterLocationChangingHandler(handler); }
catch (NotSupportedException ex) when (ex.Message.Contains("SetNavigationLockState"))
{ /* use a capable manager or skip the lock */ }

Prevention

When it happens

Trigger: RegisterLocationChangingHandler is called and the handler list transitions from empty to one entry, which calls SetNavigationLockState(true). If the concrete NavigationManager type does not override SetNavigationLockState, this NotSupportedException fires immediately on first registration.

Common situations: A test or custom host subclasses NavigationManager directly and exercises NavigationLock or RegisterLocationChangingHandler; a third-party Blazor host (e.g. a non-Microsoft MAUI/gtk host) that has not implemented navigation locking.

Related errors


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

Appendix: 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 3600ca084e)