fix: Do not parse / stringify search params that are not json objects
By default, the router parses search params using JSON.parse, regardless of whether the param is a JSON object or not. This causes strange behavior, for example, it adds quotes around numerical strings:
http://my-app.com?p=123 changes to http://my-app.com?p="123"
It also causes rounding issues when large numbers are converted into integers, for example:
http://my-app.com?p=1000000000000001110 becomes http://my-app.com?p="1000000000000001200"
Which means that resource IDs cannot be used in search params, which I guess is a common use-case.
This PR solves this by not calling the parser on params that are not json objects.
Walkthrough
Parse/stringify logic updated to avoid coercing or replacing raw string values unless a parser returns an object; qss decoding no longer coerces strings to booleans/numbers; tests updated to validate parse-first then stringify roundtrips.
Changes
| Cohort / File(s) | Summary |
|---|---|
Search params logic packages/router-core/src/searchParams.ts |
parseSearchWith now assigns parser results only when the parser returns an object; stringifySearchWith only re-stringifies when the parser returns an object, otherwise original string values are preserved. |
Query-string decoding packages/router-core/src/qss.ts |
Removed the toValue coercion helper; decode now returns raw string values (and arrays of raw strings) instead of coercing to numbers/booleans. |
Tests packages/router-core/tests/searchParams.test.ts, packages/router-core/tests/qss.test.ts |
Tests updated to parse-first then stringify for isomorphism checks; expectations adjusted to reflect raw-string decoding and arrays for repeated keys. |
Estimated code review effort
π― 3 (Moderate) | β±οΈ ~20β30 minutes
- Inspect
searchParams.tsparser branches for cases where parsers return primitives vs objects. - Verify callers of
qss.decodeand any consumers expecting coerced numeric/boolean types. - Run unit tests covering repeated keys, empty values, escaped literals, and custom parsers.
Possibly related PRs
- TanStack/router#4987 β Touches parse/stringify behavior and tests for default parse/stringify utilities; closely related test and behavior changes.
- TanStack/router#5574 β Edits the same parsing/stringifying utilities (docs/JSDoc nearby); relevant to function-level behavior.
- TanStack/router#4985 β Modifies
qss.tsandsearchParams.tsimplementations; overlaps with decode/parse behavior adjustments.
Suggested reviewers
- schiller-manuel
- SeanCassiere
Poem
"I hopped through queries, kept each string intact,
I nudged only objects where parsers interact.
Numbers no longer sneak into string beds,
Roundtrips hum softly as tests nod their heads.
β π"
Pre-merge checks and finishing touches
β Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Docstring Coverage | β Passed | Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%. |
| Title check | β Passed | The title accurately describes the main change: preventing parsing and stringifying of search params that are not JSON objects, which addresses the issue of unwanted quoting of numerical/string parameters. |
| Description Check | β Passed | Check skipped - CodeRabbitβs high-level summary is enabled. |
β¨ Finishing touches
- [ ] π Generate docstrings
π§ͺ Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
π€ Nx Cloud AI Fix Eligible
An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.
To disable these notifications, a workspace admin can disable them in workspace settings.
View your CI Pipeline Execution β for commit 1af0d4bec8c29341345245823972c5ae76475034
| Command | Status | Duration | Result |
|---|---|---|---|
nx affected --targets=test:eslint,test:unit,tes... |
β Failed | 11m 9s | View β |
nx run-many --target=build --exclude=examples/*... |
β Succeeded | 1m 20s | View β |
βοΈ Nx Cloud last updated this comment at 2025-12-01 19:37:23 UTC
More templates
- tanstack-router-solid-example-authenticated-routes
- tanstack-router-solid-example-authenticated-routes-firebase
- tanstack-router-solid-example-basic
- tanstack-router-solid-example-basic-default-search-params
- tanstack-router-solid-example-basic-devtools-panel
- tanstack-router-solid-example-basic-file-based
- tanstack-router-solid-example-basic-non-nested-devtools
- tanstack-router-solid-example-basic-solid-query
- tanstack-router-solid-example-basic-solid-query-file-based
- tanstack-router-solid-example-basic-ssr-file-based
- tanstack-router-solid-example-basic-ssr-streaming-file-based
- tanstack-router-solid-example-basic-virtual-file-based
- tanstack-router-solid-example-basic-virtual-inside-file-based
- tanstack-router-solid-example-deferred-data
- tanstack-router-solid-i18n-paraglide
- tanstack-router-solid-example-kitchen-sink
- tanstack-router-solid-example-kitchen-sink-file-based
- tanstack-router-solid-example-kitchen-sink-solid-query
- tanstack-router-solid-example-kitchen-sink-solid-query-file-based
- tanstack-router-solid-example-large-file-based
- tanstack-router-solid-example-location-masking
- tanstack-router-solid-example-navigation-blocking
- tanstack-router-solid-example-quickstart
- tanstack-router-solid-example-quickstart-esbuild-file-based
- tanstack-router-solid-example-quickstart-file-based
- tanstack-router-solid-example-quickstart-rspack-file-based
- tanstack-router-solid-example-quickstart-webpack-file-based
- router-solid-mono-simple
- router-solid-mono-simple-lazy
- router-solid-monorepo-solid-query
- tanstack-router-solid-example-scroll-restoration
- tanstack-solid-router-search-validator-adapters
- tanstack-solid-start-example-basic
- tanstack-solid-start-example-basic-auth
- tanstack-solid-start-example-basic-authjs
- tanstack-solid-start-example-basic-cloudflare
- tanstack-solid-start-example-basic-netlify
- tanstack-solid-start-example-basic-nitro
- tanstack-start-example-basic-solid-query
- tanstack-solid-start-example-basic-static
- tanstack-solid-start-bun-hosting
- tanstack-solid-start-example-convex-better-auth
- tanstack-solid-start-example-counter
- tanstack-solid-start-i18n-paraglide
- tanstack-solid-start-example-large
- tanstack-solid-start-streaming-data-from-server-functions
- tanstack-solid-start-example-supabase-basic
- tanstack-solid-start-tailwind-v4
- tanstack-router-solid-example-view-transitions
- tanstack-router-solid-example-with-framer-motion
- tanstack-router-solid-example-with-trpc
- tanstack-router-react-example-authenticated-routes
- tanstack-router-react-example-authenticated-routes-firebase
- tanstack-router-react-example-basic
- tanstack-router-react-example-basic-default-search-params
- tanstack-router-react-example-basic-devtools-panel
- tanstack-router-react-example-basic-file-based
- tanstack-router-react-example-basic-non-nested-devtools
- tanstack-router-react-example-react-query
- tanstack-router-react-example-basic-react-query-file-based
- tanstack-router-react-example-basic-ssr-file-based
- tanstack-router-react-example-basic-ssr-streaming-file-based
- tanstack-router-react-example-basic-virtual-file-based
- tanstack-router-react-example-basic-virtual-inside-file-based
- tanstack-router-react-example-deferred-data
- tanstack-router-i18n-paraglide
- tanstack-router-react-example-kitchen-sink
- tanstack-router-react-example-kitchen-sink-file-based
- tanstack-router-react-example-kitchen-sink-react-query
- tanstack-router-react-example-kitchen-sink-react-query-file-based
- tanstack-router-react-example-large-file-based
- tanstack-router-react-example-location-masking
- tanstack-router-react-example-navigation-blocking
- tanstack-router-react-example-quickstart
- tanstack-router-react-example-quickstart-esbuild-file-based
- tanstack-router-react-example-quickstart-file-based
- tanstack-router-react-example-quickstart-rspack-file-based
- tanstack-router-react-example-quickstart-webpack-file-based
- router-monorepo-react-query
- router-mono-simple
- router-mono-simple-lazy
- tanstack-router-react-example-scroll-restoration
- tanstack-search-validator-adapters
- tanstack-start-example-bare
- tanstack-start-example-basic
- tanstack-start-example-basic-auth
- tanstack-router-react-example-basic-authjs
- tanstack-start-example-basic-cloudflare
- tanstack-start-example-basic-react-query
- tanstack-start-example-basic-static
- tanstack-start-bun-hosting
- tanstack-start-example-clerk-basic
- tanstack-start-example-convex-trellaux
- tanstack-start-example-counter
- tanstack-start-i18n-paraglide
- tanstack-start-example-large
- tanstack-start-example-material-ui
- tanstack-start-streaming-data-from-server-functions
- tanstack-start-example-supabase-basic
- tanstack-start-tailwind-v4
- tanstack-start-example-trellaux
- tanstack-start-example-workos
- tanstack-router-react-example-view-transitions
- tanstack-router-react-example-with-framer-motion
- tanstack-router-react-example-with-trpc
- tanstack-router-react-example-with-trpc-react-query
@tanstack/arktype-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6000
@tanstack/directive-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@6000
@tanstack/eslint-plugin-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6000
@tanstack/history
npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6000
@tanstack/nitro-v2-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6000
@tanstack/react-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6000
@tanstack/react-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6000
@tanstack/react-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6000
@tanstack/react-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6000
@tanstack/react-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6000
@tanstack/react-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6000
@tanstack/router-cli
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6000
@tanstack/router-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6000
@tanstack/router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6000
@tanstack/router-devtools-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6000
@tanstack/router-generator
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6000
@tanstack/router-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6000
@tanstack/router-ssr-query-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6000
@tanstack/router-utils
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6000
@tanstack/router-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6000
@tanstack/server-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@6000
@tanstack/solid-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6000
@tanstack/solid-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6000
@tanstack/solid-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6000
@tanstack/solid-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6000
@tanstack/solid-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6000
@tanstack/solid-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6000
@tanstack/start-client-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6000
@tanstack/start-plugin-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6000
@tanstack/start-server-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6000
@tanstack/start-static-server-functions
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6000
@tanstack/start-storage-context
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6000
@tanstack/valibot-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6000
@tanstack/virtual-file-routes
npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6000
@tanstack/zod-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6000
commit: 1af0d4b
Fixes: https://github.com/TanStack/router/issues/6044