Skip to content

Fix catch-all router.query corruption with basePath + rewrites#93294

Merged
unstubbable merged 1 commit into
canaryfrom
hl/fix-base-path-middleware-rewrite-router-query
May 13, 2026
Merged

Fix catch-all router.query corruption with basePath + rewrites#93294
unstubbable merged 1 commit into
canaryfrom
hl/fix-base-path-middleware-rewrite-router-query

Conversation

@unstubbable
Copy link
Copy Markdown
Contributor

@unstubbable unstubbable commented Apr 27, 2026

In a Pages Router app that combines a basePath, next.config.js rewrites, middleware, and a catch-all dynamic route, a client-side Link navigation could land on the page with a corrupted router.query. Instead of holding the captured route segments, the catch-all param ended up holding the segments of the internal _next/data/<buildId>/... URL. Page code that builds further URLs from router.query then produced malformed paths and 404s in production.

The corruption originated in getMiddlewareData, which was passing nextConfig: undefined to getNextPathnameInfo whenever __NEXT_HAS_REWRITES was true. With basePath set, that meant the basePath prefix was never stripped from the data-source URL, so the /_next/data/ check never matched and the data prefix was left intact. The resulting pathname flowed back into routeInfo.resolvedAs, and on catch-all routes the route regex matched it and overwrote router.query.<param> with the data-URL segments.

The original ternary at this call site (added in #48753) was there to avoid stripping the locale prefix, since resolveRewrites needs as to keep its locale prefix to match locale-aware rewrite sources. Disabling all of nextConfig was too coarse and broke basePath stripping in the process. The fix passes a partial config with only basePath and trailingSlash, which keeps the locale prefix intact while still letting getNextPathnameInfo strip basePath before the data-prefix check.

The new test/e2e/middleware-dynamic-basepath-matcher-rewrites/ fixture is the catch-all + basePath + rewrites + middleware variant of test/e2e/middleware-dynamic-basepath-matcher/ (#48753's regression test), and asserts that router.query.path is preserved across a client-side Link navigation.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 27, 2026

Tests Passed

Commit: 8a064b5

@unstubbable unstubbable force-pushed the hl/fix-base-path-middleware-rewrite-router-query branch from 8a38ad8 to 651fe55 Compare April 28, 2026 07:40
In a Pages Router app that combines a `basePath`, `next.config.js`
`rewrites`, middleware, and a catch-all dynamic route, a client-side
`Link` navigation could land on the page with a corrupted
`router.query`. Instead of holding the captured route segments, the
catch-all param ended up holding the segments of the internal
`_next/data/<buildId>/...` URL. Page code that builds further URLs from
`router.query` then produced malformed paths and 404s in production.

The corruption originated in `getMiddlewareData`, which was passing
`nextConfig: undefined` to `getNextPathnameInfo` whenever
`__NEXT_HAS_REWRITES` was true. With basePath set, that meant the
basePath prefix was never stripped from the data-source URL, so the
`/_next/data/` check never matched and the data prefix was left intact.
The resulting pathname flowed back into `routeInfo.resolvedAs`, and on
catch-all routes the route regex matched it and overwrote
`router.query.<param>` with the data-URL segments.

The original ternary at this call site (added in #48753) was there to
avoid stripping the locale prefix, since `resolveRewrites` needs `as` to
keep its locale prefix to match locale-aware rewrite sources. Disabling
all of `nextConfig` was too coarse and broke basePath stripping in the
process. The fix passes a partial config with only `basePath` and
`trailingSlash`, which keeps the locale prefix intact while still
letting `getNextPathnameInfo` strip basePath before the data-prefix
check.

The new `test/e2e/middleware-dynamic-basepath-matcher-rewrites/` fixture
is the catch-all + basePath + rewrites + middleware variant of
`test/e2e/middleware-dynamic-basepath-matcher/` (#48753's regression
test), and asserts that `router.query.path` is preserved across a
client-side `Link` navigation.
@unstubbable unstubbable force-pushed the hl/fix-base-path-middleware-rewrite-router-query branch from 651fe55 to 8a064b5 Compare April 28, 2026 20:08
@unstubbable unstubbable marked this pull request as ready for review April 28, 2026 20:51
@unstubbable unstubbable requested review from timneutkens and ztanner and removed request for ztanner May 4, 2026 18:07
@unstubbable unstubbable merged commit f849930 into canary May 13, 2026
338 of 341 checks passed
@unstubbable unstubbable deleted the hl/fix-base-path-middleware-rewrite-router-query branch May 13, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants