Context
My diagnosis and reproduction were performed by AI, but I did initially run into the problem myself, and I verified that the reproduction reproduces the same issue I found.
What's your version of nuqs?
What framework are you using?
- ❌ Next.js (app router)
- ❌ Next.js (pages router)
- ❌ React SPA (no router)
- ❌ Remix
- ❌ React Router
- ✅ Other (please specify): TanStack Router, via
nuqs/adapters/tanstack-router, on Vite
Which version of your framework are you using?
"@tanstack/react-router": "1.170.40",
"react": "19.3.0",
"react-dom": "19.3.0",
"vite": "8.3.1",
The lockfile resolves @tanstack/router-core to 1.171.33.
Description
With NuqsAdapter from nuqs/adapters/tanstack-router, updating any nuqs param rewrites the other query params already in the URL. If another param's value contains //, such as a URL in returnUrl, the double slash is collapsed to a single slash. returnUrl is not used by any useQueryState.
Expected: only search is added, and returnUrl is untouched.
/items/123?returnUrl=https%3A%2F%2Fexample.com%2Fsome%2Fpath%3Ffoo%3D1%26bar%3D2&search=test
Actual:
/items/123?returnUrl=https:/example.com/some/path?foo=1%26bar=2&search=test
Two things are wrong:
returnUrl is no longer percent-encoded. renderQueryString leaves :, /, ? and = unescaped.
https:// has become https:/, so returnUrl is no longer a valid URL. Any param value containing // is affected, from the first update.
Likely cause: the adapter navigates with the query string embedded in to:
navigate({ from: "/", to: pathname + renderQueryString(search), ... })
to is treated as a path, so router-core's resolvePathWithBase runs cleanPath(path) on it. That does path.replace(/\/{2,}/g, '/') and also rewrites the // inside the query string.
Possibly related: #1590 looks like the same root cause with a different symptom. There the query string is appended a second time on routes with a dynamic segment.
Reproduction
StackBlitz: https://stackblitz.com/github/justinsmid/nuqs-query-params-rewrite-repro
Source: https://github.com/justinsmid/nuqs-query-params-rewrite-repro
Steps to reproduce the behavior:
- Open the StackBlitz
- Observe the correct URL
- Type anything into the search input
- See the unrelated URL query parameters become malformed
Context
My diagnosis and reproduction were performed by AI, but I did initially run into the problem myself, and I verified that the reproduction reproduces the same issue I found.
What's your version of
nuqs?What framework are you using?
nuqs/adapters/tanstack-router, on ViteWhich version of your framework are you using?
The lockfile resolves
@tanstack/router-coreto 1.171.33.Description
With
NuqsAdapterfromnuqs/adapters/tanstack-router, updating any nuqs param rewrites the other query params already in the URL. If another param's value contains//, such as a URL inreturnUrl, the double slash is collapsed to a single slash.returnUrlis not used by anyuseQueryState.Expected: only
searchis added, andreturnUrlis untouched.Actual:
Two things are wrong:
returnUrlis no longer percent-encoded.renderQueryStringleaves:,/,?and=unescaped.https://has becomehttps:/, soreturnUrlis no longer a valid URL. Any param value containing//is affected, from the first update.Likely cause: the adapter navigates with the query string embedded in
to:tois treated as a path, so router-core'sresolvePathWithBaserunscleanPath(path)on it. That doespath.replace(/\/{2,}/g, '/')and also rewrites the//inside the query string.Possibly related: #1590 looks like the same root cause with a different symptom. There the query string is appended a second time on routes with a dynamic segment.
Reproduction
StackBlitz: https://stackblitz.com/github/justinsmid/nuqs-query-params-rewrite-repro
Source: https://github.com/justinsmid/nuqs-query-params-rewrite-repro
Steps to reproduce the behavior: