Files
Hendrik LiebauandGitHub de8e2e064d Avoid mutating req.headers when stripping internal headers (#95116)
`getHeaders` in the request store strips internal flight and dev
request-id headers before sealing the object exposed to userland
`headers()`. It built that object with
`HeadersAdapter.from(req.headers)`, which wraps `IncomingHttpHeaders`
(and returns a `Headers` instance) without copying, so the `delete`
calls mutated the shared `req.headers` as a side effect.

This regressed redirects from a server action that reads `headers()`
when `cacheComponents` is enabled in `next dev`, introduced by #94703.
That change added the dev request-id headers (`x-nextjs-request-id` and
`x-nextjs-html-request-id`) to the set stripped in `getHeaders`. The
flight headers had been stripped from the shared object for a long time
without issue because their absence is a handled state, but the
request-id headers are different: the action's `headers()` access now
deleted them from `req.headers`, and the dev instant-navigation render
of the redirect target, which reuses the same request, then read a
missing request id and fabricated a mismatched HTML request id. The
React dev debug channel was registered under that wrong id, so the
client overlay stayed in "Rendering..." and never applied the
navigation.

This change copies the headers before stripping so only the sealed
userland view is affected, leaving the shared request headers intact. It
adds an e2e test that reproduces the regression.

fixes #95103
2026-06-24 12:02:38 +02:00
..
…