Soft navigation leaves the previous route's metadata mounted in head (duplicate og/twitter tags) on Vercel with 16.3
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.4k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/brookton/next-soft-nav-metadata-repro
To Reproduce
- Deploy the linked app to Vercel.
- As soon as the deployment is READY, open
/in a browser. - Click "Article one" (client-side navigation; the link prefetches).
- In devtools, run:
[...document.head.querySelectorAll('meta[property="og:type"]')].map((m) => m.content);
Buggy result: ["website", "article"]. Every og:*, twitter:*, and description tag is present twice, previous route's values plus new route's values.
Timing matters: reproduction is reliable in the first minutes after a deployment, while the route's prefetch responses are served cold (x-vercel-cache: PRERENDER). Once those entries warm, the same flow is usually clean, so redeploy to re-enter the window. In our production app's CI, where Playwright runs minutes after each preview deployment, the failure reproduced on 100% of attempts including retries.
Current vs. Expected behavior
Current: after a soft navigation, the previous route's entire resolved metadata block stays mounted in <head> alongside the new route's block, so meta[property="og:type"] resolves to two elements (website and article). The state persists (verified 8+ seconds after navigation) and never self-corrects.
Expected: the new route's metadata replaces the previous route's, matching what a hard load of the same URL produces (a single correct set).
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.6.0
Binaries:
Node: 24.11.1
npm: 11.6.2
Relevant Packages:
next: 16.3.1
react: 19.2.7
react-dom: 19.2.7
typescript: 5.9.3
Affected: 16.3.0 and 16.3.1. Not affected: 16.2.12 (same app, same fresh-deployment CI window, all browsers pass).
Which area(s) are affected?
Metadata, Navigation
Which stage(s) are affected?
Vercel (Deployed)
Additional context
Evidence gathered on a production app (five-browser Playwright CI plus scripted Chromium against the preview deployment):
- Server HTML is always correct. Curling the deployed pages and a local
next build && next startrender shows exactly one metadata set, and hard reloads in the browser are always clean. The defect is purely client-side head reconciliation during soft navigation. - Blocking prefetch requests in the browser (aborting requests carrying
Next-Router-Prefetch: 1) makes the identical navigation clean, implicating the prefetch payload path. Artificially delaying prefetch responses does not reproduce it, so it is not a simple in-flight race. - In the failing runs, the destination route's RSC prefetches were served with
x-vercel-cache: PRERENDER. We could never reproduce against localnext start, with cold or warm caches. - Browser split in the same CI pipeline on the same commit: chrome, ios (iPhone 12 emulation), and android (Pixel 5 emulation) failed on every retry while desktop safari and firefox passed, consistent with per-job prefetch/cache state rather than engine differences.
- 16.3.1's client segment-cache changes relative to 16.3.0 (metadata-only request tree guard, per-navigation cache map) do not fix it.
- Closest existing report appears to be #95347 (metadata boundary resume mismatch), but the signature differs.
Happy to provide Playwright traces (DOM snapshots and network logs) from the failing CI runs.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Deploy the linked next-soft-nav-metadata-repro app to Vercel and reproduce the issue during the cold prefetch window. Compare soft navigation with a hard load and with Next.js 16.2.12, inspecting the document head and prefetch responses. Done means the destination route replaces the previous metadata with one correct set, matching hard-load behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nextjs, react
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100