Skip to content

fix(router-core): preserve string search params that don't survive JSON.parse numeric round-trip#7652

Open
JSap0914 wants to merge 1 commit into
TanStack:mainfrom
JSap0914:fix/parsesearch-numeric-roundtrip-loss
Open

fix(router-core): preserve string search params that don't survive JSON.parse numeric round-trip#7652
JSap0914 wants to merge 1 commit into
TanStack:mainfrom
JSap0914:fix/parsesearch-numeric-roundtrip-loss

Conversation

@JSap0914

@JSap0914 JSap0914 commented Jun 18, 2026

Copy link
Copy Markdown

Bug

parseSearchWith(JSON.parse) destructively coerces search-param strings whose raw value happens to be valid JSON scientific notation or a large integer:

defaultParseSearch('?codAut=662E41')
// actual:   { codAut: 6.62e+43 }    ← irreversible, lossy
// expected: { codAut: '662E41' }

defaultParseSearch('?id=723421968459640832')
// actual:   { id: 723421968459640800 }  ← precision loss
// expected: { id: '723421968459640832' }

The root cause: JSON.parse('662E41') succeeds (it is valid JSON scientific notation: 662 × 10⁴¹), but String(6.62e+43) !== '662E41', so the original string is irrecoverably destroyed before validateSearch ever runs.

Fixes #7650.

Fix

Add a numeric round-trip guard in parseSearchWith: after parser(value) returns a number, only accept it when String(parsed) === value. If the round-trip fails, the original string is kept instead.

Lossless cases like '123' → 123 (where String(123) === '123') are unaffected.

The fix is purely additive — no existing tests needed editing.

Verification

pnpm --filter @tanstack/router-core exec vitest run tests/searchParams.test.ts

Test Files 1 passed (1)
Tests 41 passed (41) — 40 original + 1 new

AI-assisted contribution.

Summary by CodeRabbit

Bug Fixes

  • Fixed query parameter parsing to preserve the original string format for numeric values that would not round-trip correctly (such as scientific notation or large integers). Values that change their representation when converted back to strings are now kept as original strings to prevent unintended data loss.

…ON.parse numeric round-trip

parseSearchWith(JSON.parse) destructively coerced any search-param string
whose raw value was a valid JSON number. Examples:

  '662E41' (hex/auth code) → 6.62e+43   (irreversible, lossy)
  '723421968459640832'     → 723421968459640800  (precision loss)

The issue: String(6.62e+43) !== '662E41', so the original string cannot
be recovered after the conversion.

Fix: after JSON.parse succeeds, if the result is a number and String(result)
does not equal the original string, skip the assignment and keep the original
string. Lossless numeric conversions (e.g. '123' → 123) are unaffected.

Fixes TanStack#7650
Copilot AI review requested due to automatic review settings June 18, 2026 17:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea9f9877-1135-457c-b49a-68f7e8a16372

📥 Commits

Reviewing files that changed from the base of the PR and between ac821f4 and eb7a4e1.

📒 Files selected for processing (3)
  • .changeset/parsesearch-numeric-roundtrip.md
  • packages/router-core/src/searchParams.ts
  • packages/router-core/tests/searchParams.test.ts

📝 Walkthrough

Walkthrough

parseSearchWith in searchParams.ts gains a numeric round-trip guard: after parsing a string query value, if the result is a number whose String() representation does not exactly match the original input, the original string is kept. A new test and a changeset entry accompany the fix.

Changes

parseSearchWith Numeric Round-Trip Guard

Layer / File(s) Summary
Round-trip guard implementation and tests
packages/router-core/src/searchParams.ts, packages/router-core/tests/searchParams.test.ts, .changeset/parsesearch-numeric-roundtrip.md
parseSearchWith now preserves the original string when parser returns a number that would not reproduce the original input via String(). Tests assert that 662E41, large unsafe integers, and 9e3 stay as strings while 42 is still parsed as a number. Changeset documents the patch for @tanstack/router-core.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested labels

package: router-core

Suggested reviewers

  • chorobin

Poem

🐇 Hop hop, the numbers tried to sneak,
Disguised as strings — quite bold, quite cheeky!
But now we check: does String(n) match?
If not, we keep the original batch.
No more lost auth codes, no HMAC grief —
The round-trip guard brings sweet relief! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: adding a numeric round-trip check to preserve search parameter strings that would be corrupted by JSON.parse conversion.
Linked Issues check ✅ Passed The implementation fully addresses issue #7650 by adding a round-trip guard that preserves string values when JSON.parse yields a number whose string representation differs from the original input.
Out of Scope Changes check ✅ Passed All changes directly address the linked issue: the round-trip guard implementation in searchParams.ts, the new test case for numeric round-trip behavior, and the changesets entry are all in scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

defaultParseSearch corrupts string search params that look like JSON numbers (e.g. "662E41", large integers) — lossy and unrecoverable on inbound URLs

2 participants