[🐞] routeLoader$({ search: [] }) drops route params when the request has a query string
### Which component is affected?
Qwik Router
### Describe the bug
On a dynamic route (e.g. `/[lang]/index.tsx`), a `routeLoader$` declared
with the `{ search: [] }` option receives an **empty `params` object** as
soon as the request URL carries any query string — even though the exact
same request without a query string resolves `params` correctly.
This isn't just a 404/routing bug — it's `params` silently getting lost.
Any application code that reads `params.xxx` inside such a loader gets
`undefined`/empty values whenever a visitor's URL has a query parameter
(tracking params, search, a redirect token, etc.), with no error raised. In
our real app it does surface as a hard 404, only because our loader
explicitly validates the param and rejects the request when it's missing —
but the root cause is the lost `params`, not routing itself.
Also observed inside the loader (via a temporary `console.error`): with the
query string present, the loader's own `url.href` has *also* dropped the
query string entirely — it reads back as the bare path. This is consistent
with `search: []`'s documented behavior of filtering the URL handed to the
loader (per the `LoaderOptions.search` doc comment), except it appears to
also lose the route's own path params in the process.
We found this while migrating a production app from beta.38 to beta.40
(Vite 8/Rolldown). **It reproduces identically on beta.39 with Vite 7**, so
it predates that migration and is unrelated to the Vite 8/Rolldown switch —
just flagging that clearly since beta.40 was announced right before we hit
this.
### Isolating the cause
Confirmed on a clean 2-file repro (`npm create qwik@beta`, nothing from our
real app):
- Removing the `{ search: [] }` option from the loader makes the bug
disappear — `params.lang` stays correct regardless of the query string.
Everything else in the file is unchanged.
- The starter's root route `/` (no dynamic segment, no `search` option) is
never affected, with or without a query string.
- `strictLoaders` (the `qwikRouter()` plugin option) does **not** matter —
reproduced identically with the default (`true`) and with
`strictLoaders: false`.
### Reproduction
https://github.com/tidiview/qwik-router-query-404-repro
### Steps to reproduce
1. `npm install`
2. `npm run dev`
3. In another terminal:
```
curl -s http://localhost:5173/fr/ # → "lang param = \"fr\"" (correct)
curl -s http://localhost:5173/fr/?foo=bar # → "lang param = null" (BUG: params lost)
```
Also reproduces the same way under `npm run build` + a Cloudflare Pages
adapter build served via `wrangler pages dev` (production build, not just
dev SSR).
### System Info
```shell
System:
OS: Windows 10 10.0.19045
Binaries:
Node: 24.7.0
npm: 11.5.1
npmPackages:
@qwik.dev/core: ^2.0.0-beta.40 => 2.0.0-beta.40
@qwik.dev/router: ^2.0.0-beta.40 => 2.0.0-beta.40
typescript: 5.9.3 => 5.9.3
vite: 8.2.1 => 8.2.1
```
Also reproduced with `@qwik.dev/core`/`@qwik.dev/router` `2.0.0-beta.39` and
`vite@7.3.2`.
### Additional Information
Happy to add more detail or test a fix against our real app — this is
currently blocking us from moving past beta.38 in production, since our
`/[lang]/` route uses `search: []` on its loader and validates
`params.lang`, so every request to that page carrying a query string (our
edit flow's POST/redirect/GET pattern uses one) gets a hard 404.
0 条评论