dotnet/aspnetcore · error · InvalidOperationException

The type {NotFoundPage.FullName} does not have a Microsoft.A

Error message

The type {NotFoundPage.FullName} does not have a Microsoft.AspNetCore.Components.RouteAttribute applied to it.

What it means

Thrown in Router.SetParametersAsync when NotFoundPage is set but the type has no [RouteAttribute] (i.e., no @page directive). The Router reads the type's [Route] attribute to derive the not-found route; without one it cannot route to it, so it rejects the configuration.

Source

Thrown at src/Components/Components/src/Routing/Router.cs:155

        if (NotFoundPage != null)
        {
#pragma warning disable CS0618 // Type or member is obsolete
            if (NotFound != null)
            {
                throw new InvalidOperationException($"Setting {nameof(NotFound)} and {nameof(NotFoundPage)} properties simultaneously is not supported. Use either {nameof(NotFound)} or {nameof(NotFoundPage)}.");
            }
#pragma warning restore CS0618 // Type or member is obsolete
            if (!typeof(IComponent).IsAssignableFrom(NotFoundPage))
            {
                throw new InvalidOperationException($"The type {NotFoundPage.FullName} " +
                    $"does not implement {typeof(IComponent).FullName}.");
            }

            var routeAttributes = NotFoundPage.GetCustomAttributes(typeof(RouteAttribute), inherit: true);
            if (routeAttributes.Length == 0)
            {
                throw new InvalidOperationException($"The type {NotFoundPage.FullName} " +
                    $"does not have a {typeof(RouteAttribute).FullName} applied to it.");
            }

            var routeAttribute = (RouteAttribute)routeAttributes[0];
            if (routeAttribute.Template != null)
            {
                _notFoundPageRoute = routeAttribute.Template;
            }
        }

        if (!_onNavigateCalled)
        {
            _onNavigateCalled = true;
            await RunOnNavigateAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), isNavigationIntercepted: false);
        }
        else
        {
            Refresh(isNavigationIntercepted: false);

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Add a @page directive to the NotFoundPage component, e.g. @page "/404" (the exact path is not critical; the Router uses it as the route key).
  2. Confirm the [Route] attribute is present via NotFoundPage.GetCustomAttributes(typeof(RouteAttribute), inherit: true).
  3. Rebuild so the route attribute is emitted on the generated component class.

Example fix

<!-- before: NotFound.razor -->
<h1>Not found</h1>

<!-- after: NotFound.razor -->
@page "/404"
<h1>Not found</h1>
Defensive patterns

Strategy: validation

Validate before calling

static bool HasRouteAttribute(Type t) =>
    t.GetCustomAttributes(typeof(RouteAttribute), inherit: true).Length > 0;
// Only bind NotFoundPage if it has a [Route]/@page.
<Router ... NotFoundPage="@(HasRouteAttribute(typeof(NotFound)) ? typeof(NotFound) : null)" />

Type guard

static bool IsRoutedComponent(Type t) =>
    typeof(IComponent).IsAssignableFrom(t) &&
    t.GetCustomAttributes(typeof(RouteAttribute), inherit: true).Length > 0;

Prevention

When it happens

Trigger: Setting NotFoundPage="@typeof(NotFound)" where NotFound.razor lacks an @page directive. The Router expects at least one [Route] on the type to use as its _notFoundPageRoute.

Common situations: Creating a dedicated 404 component but forgetting @page; an older sample where the 404 page had no route; refactoring that removed the @page line.

Related errors


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