dotnet/aspnetcore · error · InvalidOperationException

The type does not implement .

Error message

The type {context.Handler.FullName} does not implement {typeof(IComponent).FullName}.

What it means

At navigation time the Router resolves the location against its route table; if a handler matches but that handler type does not implement IComponent, the router throws InvalidOperationException before attempting to render. This is the runtime counterpart to the constructor-time RouteData check — it catches corruption introduced between table construction and navigation, e.g. by a route keying bug or a stray entry from a non-component assembly.

Solutions

  1. Audit the assemblies contributing routes; ensure only Blazor components are registered as handlers.
  2. Inspect the named type in the exception — if it is a controller or model, exclude that assembly from the Router's AdditionalAssemblies or filter the [Route] contributor.
  3. If you provide custom route entries, gate them on typeof(IComponent).IsAssignableFrom(handler).
  4. Clear route caches after a hot-reload that changes a type's base hierarchy.

Example fix

// before — custom route provider registers a non-component
entries.Add(new InboundRouteEntry { Handler = typeof(UserApi), ... });
// after
if (typeof(IComponent).IsAssignableFrom(typeof(UserPage)))
    entries.Add(new InboundRouteEntry { Handler = typeof(UserPage), ... });
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard custom route providers before adding entries.
if (!typeof(IComponent).IsAssignableFrom(context.Handler))
    throw new InvalidOperationException($"{context.Handler} is not a component; refusing to register.");

Type guard

static bool IsRouteHandler(Type t) => typeof(IComponent).IsAssignableFrom(t);

Prevention

When it happens

Trigger: A route context whose Handler is set to a type that is not a component — typically because route discovery picked up an attribute on a non-component type, or because route table entries were mutated. Fires inside the navigation path after Routes.Route(context) resolves a handler.

Common situations: Custom route providers or IRouteDefinitionResolver implementations that emit entries for non-component types; assembly scanning that included MVC controllers or Razor Pages models decorated with a compatible attribute; a stale route table after hot-reload of a type into a non-component form.

Related errors


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

Appendix: source

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

            _renderHandle.Render(Found(endpointRouteData));

            if (ComponentsActivitySource.IsSupported && _renderHandle.ComponentActivitySource != null)
            {
                _renderHandle.ComponentActivitySource.StopNavigateActivity(activityHandle, null);
            }
            return;
        }

        RefreshRouteTable();

        var context = new RouteContext(locationPath);
        Routes.Route(context);

        if (context.Handler != null)
        {
            if (!typeof(IComponent).IsAssignableFrom(context.Handler))
            {
                throw new InvalidOperationException($"The type {context.Handler.FullName} " +
                    $"does not implement {typeof(IComponent).FullName}.");
            }

            activityHandle = RecordDiagnostics(context.Handler.FullName, context.Entry.RoutePattern.RawText);

            Log.NavigatingToComponent(_logger, context.Handler, locationPath, _baseUri);

            var routeData = new RouteData(
                context.Handler,
                context.Parameters ?? _emptyParametersDictionary);

            _renderHandle.Render(Found(routeData));

            // If you navigate to a different path, then after the next render we'll update the scroll position
            if (relativePath != _updateScrollPositionForHashLastLocation)
            {
                _updateScrollPositionForHashLastLocation = relativePath.ToString();
                _updateScrollPositionForHash = true;

View on GitHub (pinned to 3600ca084e)