dotnet/aspnetcore · error · InvalidOperationException
The type does not implement .
Error message
The type {NotFoundPage.FullName} does not implement {typeof(IComponent).FullName}. What it means
When NotFoundPage is set, Router validates the type implements IComponent, because it will be rendered through the component pipeline (it must be a real routable component, not an arbitrary type). The check runs during SetParametersAsync immediately after the mutual-exclusion check. A non-component type would fail later with an opaque cast, so the type check fails fast.
Solutions
- Verify the type passed to NotFoundPage is a Razor component (has a .razor file or implements IComponent directly).
- If the desired 404 page is plain markup, create a new .razor component and reference that.
- Filter candidate types with typeof(IComponent).IsAssignableFrom(t) before assigning.
Example fix
// before
<Router AppAssembly="@typeof(Program).Assembly"
NotFoundPage="@typeof(NotFoundViewModel)"> // a POCO, not a component
// after
<Router AppAssembly="@typeof(Program).Assembly"
NotFoundPage="@typeof(NotFound)"> // NotFound.razor implements IComponent Defensive patterns
Strategy: type-guard
Validate before calling
if (notFoundPage is not null && !typeof(IComponent).IsAssignableFrom(notFoundPage))
throw new InvalidOperationException($"{notFoundPage} must implement IComponent."); Type guard
static bool IsRoutableComponent(Type? t)
=> t is not null && typeof(IComponent).IsAssignableFrom(t)
&& t.GetCustomAttributes(typeof(RouteAttribute), inherit: true).Length > 0; Prevention
- Only point NotFoundPage at .razor components or classes implementing IComponent.
- Keep an inventory of components used as not-found targets.
- Add a unit test that asserts the configured NotFoundPage type implements IComponent.
When it happens
Trigger: Setting NotFoundPage to a typeof(...) that is a plain class, model, controller, or Razor Page (MVC) rather than a Blazor component.
Common situations: Pointing NotFoundPage at an MVC view or Razor Pages model by mistake; using a base class or layout type that is not itself a component; refactor that turned a component into a non-component type while the Router reference was unchanged.
Related errors
- Setting and properties simultaneously is not supported. Use…
- The type does not implement .
- The type does not have a applied to it.
- No component found for route
- The component requires a value for the parameter .
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/2e61030c20256a44.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Components/src/Routing/Router.cs:148
// Found content is mandatory, because even though we could use something like <RouteView ...> as a
// reasonable default, if it's not declared explicitly in the template then people will have no way
// to discover how to customize this (e.g., to add authorization).
if (Found == null)
{
throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(Found)}.");
}
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)View on GitHub (pinned to 3600ca084e)