Repository navigation
Description
Use case
As a developer
- Given I declare two separate routes with the same path
- When, I run
go_router_builder - Then, I want to know about my mistake at build time so I can fix it. Otherwise, I run into unexpected behavior at runtime.
Current behavior
First declared wins, but not always. I tested all three cases against go_router 17.3.0.
Duplicate leaf paths: the first wins, the second is dead. Configuration._getLocRouteMatches walks the root routes in declaration order and returns the first non-empty result (configuration.dart:395-405). Children do the same and break on the first hit (match.dart:264-277). Two details leaves under /home, and /home/details renders the first.
Paths differing only in parameter name: same, first wins. /meal/:id before /meal/:mealId, navigating to /meal/7 renders the first and populates id with 7. The second builder never runs, so mealId is never read. A failed attempt doesn't leak parameters either, since each route stages them in a temp map and merges only once it's part of the result (match.dart:216-225).
Duplicate paths with different children: the second is reachable. This is the one that breaks the simple story. Matching backtracks. A route that matches a prefix but whose children can't complete the URL returns empty (match.dart:278-282), and the sibling loop keeps going. So with:
/home
details -> [a]
details -> [b]
/home/details/b reaches child b through the second details. I confirmed it renders. /home/details on its own still resolves to the first.
Proposal
- Detect the conflict in
go_router_builderand report it at build time. Two routes conflict when they compete for the same URL namespace and their paths normalize to the same pattern, someal/:idandmeal/:mealIdcount as one pattern. - Resolve namespaces per level of the route tree. Shell routes and
StatefulShellRoutebranches own no path, so the routes inside them compete with the routes around them. Relative routes own their path like any other route. Separate annotations compete, since$appRoutescollects them into one list. A library includes itspartfiles, which covers an app's whole route table given it has to live in one library today ([go_router_builder] Define routes in separate files #122258). - Report rather than fail, by default. The third case above works at runtime, because matching backtracks, so a hard error would fail the build of an app that runs correctly. Same for one route class declared twice with different children, which is a way to group children by feature area. Every route still generates and the author decides what to do.
- Make the severity configurable with a
duplicate_route_pathsbuilder option, acceptingwarning(the default),error, andignore. Teams whose duplicates are always mistakes get a hard failure, and teams using the grouping pattern setignore. Package-wide, with no per-route escape hatch. - Worth noting the check has already earned its keep:
go_router_builder's own example app registeredDoubleRoutetwice since [go_router_builder] Adds support for enhanced enums. packages#2395 (2022) andDoubleExtensionRoutetwice since [go_router_builder] Support extension types packages#9458 (2025). Both duplicates were unreachable, and removing them changed nothing but the dead entries in the generated route list.
Activity
[go_router_builder] Report duplicate route paths at build time (flutt…
[go_router_builder] Report duplicate route paths at build time (flutt…
[go_router_builder] Report duplicate route paths at build time (flutt…
github-actions commentedon Sep 16, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.