nextjs - ✅(Solved) Fix Object.fromEntries(URLSearchParams) drops duplicate keys → stale UI on navigation [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#92787Fetched 2026-04-16 06:34:37
View on GitHub
Comments
0
Participants
1
Timeline
7
Reactions
0
Participants
Timeline (top)
cross-referenced ×2referenced ×2issue_type_added ×1labeled ×1

PR fix notes

PR #92810: fix(app-router): preserve duplicate search-param keys in ppr cache key

Description (problem / solution / changelog)

Per #92787, ppr-navigations.ts stringified the search params via Object.fromEntries(new URLSearchParams(...)), which silently drops duplicate keys. Navigating from ?color=red&color=blue to ?color=blue produced an identical cache key, so the router skipped re-rendering and the UI stayed stale.

Build the cache-key object via URLSearchParams.getAll() so duplicate keys produce an array entry, making the keys distinct across navigations that change the multiplicity of a query parameter. Single-value keys still serialise as a string, so the cache key shape is unchanged for the common case.

Closes #92787

<!-- NEXT_JS_LLM_PR -->

Changed files

  • packages/next/src/client/components/router-reducer/ppr-navigations.ts (modified, +4/-2)
  • packages/next/src/client/components/segment-cache/scheduler.ts (modified, +2/-1)
  • packages/next/src/client/route-params.ts (modified, +2/-1)
  • packages/next/src/shared/lib/segment.ts (modified, +19/-0)

PR #92818: fix(router): preserve duplicate search params in ChildSegmentMap cache keys

Description (problem / solution / changelog)

What?

Fixes navigation stale UI when multi-value (repeated) search params are used (e.g. ?color=red&color=blue).

Why?

Object.fromEntries(new URLSearchParams(search)) silently drops all but the last value for repeated keys — for example ?color=red&color=blue becomes {color:"blue"}, which is the same as ?color=blue. This causes distinct URLs to share the same ChildSegmentMap cache entry, resulting in stale UI on navigation.

The server-side addSearchParamsIfPageSegment receives a proper Record<string, string | string[]> (from NextParsedUrlQuery) where repeated keys are stored as arrays. The client-side code should produce the same representation.

How?

Replace Object.fromEntries(new URLSearchParams(...)) with an explicit loop using URLSearchParams.getAll() to build a Record<string, string | string[]> that preserves duplicate keys as arrays. Applied in both:

  • packages/next/src/client/components/router-reducer/ppr-navigations.ts — the cache key for ChildSegmentMap entries
  • packages/next/src/client/components/segment-cache/scheduler.ts — segment matching during cache lookup

Fixes #92787

Changed files

  • packages/next/src/client/components/router-reducer/ppr-navigations.ts (modified, +13/-3)
  • packages/next/src/client/components/segment-cache/scheduler.ts (modified, +9/-1)

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.1.0: Mon Oct 20 19:32:41 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T6000
  Available memory (MB): 16384
  Available CPU cores: 10
Binaries:
  Node: 24.6.0
  npm: 11.5.1
  Yarn: 1.22.19
  pnpm: 10.18.3
Relevant Packages:
  next: 16.2.1-canary.38 // Latest available version is detected (16.2.1-canary.38).
  eslint-config-next: N/A
  react: 19.2.5
  react-dom: 19.2.5
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/krivcikfilip/next-multi-searchparams-bug

To Reproduce

  1. npm install && npm run dev
  2. Click "+ red" → /?color=red (2 items) ✅
  3. Click "+ blue" → /?color=red&color=blue (4 items) ✅
  4. Click "✕ red" → /?color=blue — still 4 items ❌ (should be 2)

Current vs. Expected behavior

ppr-navigations.ts uses Object.fromEntries(new URLSearchParams(search)) for cache keys. Object.fromEntries keeps only the last value per key, so:

"?color=red&color=blue" → {color: "blue"} "?color=blue" → {color: "blue"}

Same key → cache hit → no re-render.

Fix: replace Object.fromEntries() with a method preserving all values (e.g. getAll()).

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.1.0: Mon Oct 20 19:32:41 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T6000
  Available memory (MB): 16384
  Available CPU cores: 10
Binaries:
  Node: 24.6.0
  npm: 11.5.1
  Yarn: 1.22.19
  pnpm: 10.18.3
Relevant Packages:
  next: 16.2.1-canary.38 // Latest available version is detected (16.2.1-canary.38).
  eslint-config-next: N/A
  react: 19.2.5
  react-dom: 19.2.5
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Linking and Navigating

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

No response

extent analysis

TL;DR

Replace Object.fromEntries(new URLSearchParams(search)) with a method that preserves all query parameter values to fix the caching issue.

Guidance

  • Identify the current implementation of cache key generation in ppr-navigations.ts and verify that it uses Object.fromEntries(new URLSearchParams(search)).
  • Replace Object.fromEntries with an alternative method, such as using URLSearchParams's getAll method to preserve all values for each key.
  • Test the updated implementation by reproducing the steps in the "To Reproduce" section and verifying that the expected behavior is achieved.
  • Consider logging or debugging the cache keys generated by the new implementation to ensure they are correct and unique.

Example

const searchParams = new URLSearchParams(search);
const cacheKey = {};
for (const [key, value] of searchParams) {
  if (!cacheKey[key]) {
    cacheKey[key] = [];
  }
  cacheKey[key].push(value);
}

Notes

This solution assumes that the issue is solely caused by the use of Object.fromEntries and that preserving all query parameter values will fix the caching issue. However, the actual implementation may require additional considerations, such as handling edge cases or optimizing performance.

Recommendation

Apply workaround: Replace Object.fromEntries with an alternative method that preserves all query parameter values, as this directly addresses the identified cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING