dotnet/aspnetcore · error · InvalidOperationException
The type {NotFoundPage.FullName} does not have a {typeof(Rou
Error message
The type {NotFoundPage.FullName} does not have a {typeof(RouteAttribute).FullName} applied to it. What it means
Router also requires the NotFoundPage type to carry a [Route] attribute (its route template is captured to drive the 404 navigation). The check fetches custom attributes of type RouteAttribute and throws if none are present. Without a [Route] the router cannot build a route entry for the not-found page, so the configuration is rejected at startup.
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 3600ca084e)
Solutions
- Add @page "/not-found" (or equivalent [Route("/not-found")]) to the top of the component referenced by NotFoundPage.
- Confirm the attribute survives trimming/publishing — attributes on the type are required at runtime.
- Pick a different component that already has a [Route].
Example fix
// before — NotFound.razor has no @page <h1>404</h1> // after @page "/not-found" <h1>404</h1>
Defensive patterns
Strategy: type-guard
Validate before calling
var attrs = notFoundPage?.GetCustomAttributes(typeof(RouteAttribute), inherit: true);
if (attrs is null || attrs.Length == 0)
throw new InvalidOperationException($"{notFoundPage} needs a [Route] attribute."); Type guard
static bool HasRouteAttribute(Type? t)
=> t?.GetCustomAttributes(typeof(RouteAttribute), inherit: true).Length > 0; Prevention
- Always add @page "/not-found" (or another route) to the component used as NotFoundPage.
- Add a unit test asserting the NotFoundPage type carries a [Route].
- When trimming, ensure route attributes are preserved on the not-found component.
When it happens
Trigger: Setting NotFoundPage to a component type that has no [Route("...")] attribute on it (e.g. a layout component or a non-routed component).
Common situations: Reusing a layout or shared component as the 404 page; creating a NotFound component and forgetting the @page directive; refactoring a component and removing its @page thinking it is unused.
Related errors
- Setting {nameof(NotFound)} and {nameof(NotFoundPage)} proper
- The type {NotFoundPage.FullName} does not implement {typeof(
- The {nameof(Router)} component requires a value for the para
- The {nameof(Router)} component requires a value for the para
- The type {context.Handler.FullName} does not implement {type
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/009219d27f078456.
Report an issue: GitHub.