dotnet/aspnetcore · error · InvalidOperationException

The following routes are ambiguous: '{existingText}' in '{ex

Error message

The following routes are ambiguous:
'{existingText}' in '{existing.Handler.FullName}'
'{currentText}' in '{current.Handler.FullName}'

What it means

Thrown by RouteTableFactory.DetectAmbiguousRoutes when two InboundRouteEntry entries are equal under InboundRouteEntryAmbiguityEqualityComparer (same route pattern). The router disallows two components resolving the same URL because it could not pick one deterministically, so the conflict is reported at route-table build time.

Source

Thrown at src/Components/Components/src/Routing/RouteTableFactory.cs:214

            RoutePattern = parsedTemplate,
            UnusedRouteParameterNames = GetUnusedParameterNames(result.AllRouteParameterNames, routeParameterNames!),
        };
    }
    private static void DetectAmbiguousRoutes(TreeRouteBuilder builder)
    {
        var seen = new HashSet<InboundRouteEntry>(new InboundRouteEntryAmbiguityEqualityComparer());
        seen.EnsureCapacity(builder.InboundEntries.Count);

        for (var i = 0; i < builder.InboundEntries.Count; i++)
        {
            var current = builder.InboundEntries[i];

            if (!seen.Add(current))
            {
                seen.TryGetValue(current, out var existing);
                var existingText = existing!.RoutePattern.RawText!.Trim('/');
                var currentText = current.RoutePattern.RawText!.Trim('/');
                throw new InvalidOperationException($"""
                    The following routes are ambiguous:
                    '{existingText}' in '{existing.Handler.FullName}'
                    '{currentText}' in '{current.Handler.FullName}'

                    """);
            }
        }
    }

    private static HashSet<string> GetParameterNames(RoutePattern routeTemplate)
    {
        var parameterNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        foreach (var parameter in routeTemplate.Parameters)
        {
            parameterNames.Add(parameter.Name!);
        }

        return parameterNames;

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Search all @page directives in the solution for the duplicated template (the message names both conflicting components).
  2. Change one component's @page template so the routes differ.
  3. If one definition is obsolete, remove the [Route]/@page from it or exclude the assembly from the Router's AppAssembly/AdditionalAssemblies.

Example fix

<!-- before: Component A -->
@page "/users"
<!-- before: Component B -->
@page "/users"

<!-- after -->
@page "/users"      <!-- Component A -->
@page "/users/list" <!-- Component B -->
Defensive patterns

Strategy: validation

Validate before calling

// At startup/test, scan all @page templates across the Router's assemblies for duplicates.
static IEnumerable<string> DuplicateRoutes(params Assembly[] assemblies) =>
    assemblies.SelectMany(a => a.GetTypes())
        .SelectMany(t => t.GetCustomAttributes(typeof(RouteAttribute), true)
            .Cast<RouteAttribute>().Select(ra => ra.Template?.TrimEnd('/')))
        .GroupBy(r => r, StringComparer.OrdinalIgnoreCase)
        .Where(g => g.Count() > 1).Select(g => g.Key);

Prevention

When it happens

Trigger: Two components in the scanned assemblies declare @page "/same/path" (identical template). Fires when the Router builds its route table on first navigation, scanning AppAssembly (+ AdditionalAssemblies).

Common situations: Copy-pasting a page and forgetting to change its @page; two assemblies in AdditionalAssemblies both defining the same route; a shared library and the app both declaring a route; case-only differences that the equality comparer treats as duplicates.

Related errors


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