Skip to content

Conversation

@pieh
Copy link
Contributor

@pieh pieh commented Dec 17, 2025

Description

There is Next.js quirk where it sets or appends location header multiple times. In specific cases it first set it and then append it, which results in location header being twice in response. When using next start this doesn't seem to cause actual problems, however you can see location header twice:

$ curl -v http://localhost:3000/page-that-uses-redirect-from-next/navigation
[...]
< location: /test/123
< location: /test/123

Despite the weirdness browsers work fine with it.

We however adapt NF's Fetch API Request and Response to (req: http.IncomingMessage, res: http.ServerResponse) pair used under the hood by Next.js.

Fetch API Headers have different behavior - it will create single header with , delimeter ( https://github.com/nodejs/undici/blob/59fd5f4ee6b2da75cf5365c06c7a409f7ba3b206/lib/web/fetch/headers.js#L246-L250 )
which result in reponses like so:

$ curl -v https://some-netlify-project/page-that-uses-redirect-from-next/navigation
[...]
< location: /test/123, /test/123

which breaks browser's behavior.

This adds a workaround to res.appendHeader that we pass to Next.js to disallow appending same location again

Documentation

Tests

Added test case for the scenario in first commit (failing without code changes)

@pieh pieh added the test all versions Run e2e tests against old and canary versions of Next.js label Dec 17, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 17, 2025

📊 Package size report   0.03%↑

File Before (Size / Gzip) After (Size / Gzip)
dist/run/augment-next-response.js 1.8 kB / 661 B
dist/run/handlers/server.js 142.9 kB / 33.5 kB 0.01%↑142.9 kB / 0.01%↑33.5 kB
dist/run/revalidate.js 1.0 kB / 479 B
Total (Includes all files) 2.9 MB / 824.4 kB 0.03%↑2.9 MB / 0.02%↑824.6 kB
Tarball size 781.4 kB 0.01%↑781.5 kB
Unchanged files
File Size (Size / Gzip)
dist/build/advanced-api-routes.js 4.6 kB / 1.4 kB
dist/build/cache.js 1.0 kB / 416 B
dist/build/content/next-shims/telemetry-storage.cjs 1.6 kB / 659 B
dist/build/content/prerendered.js 11.5 kB / 3.2 kB
dist/build/content/server.js 12.6 kB / 3.7 kB
dist/build/content/static.js 4.2 kB / 1.4 kB
dist/build/functions/edge.js 24.9 kB / 6.6 kB
dist/build/functions/server.js 4.9 kB / 1.6 kB
dist/build/image-cdn.js 54.0 kB / 11.1 kB
dist/build/plugin-context.js 13.4 kB / 3.8 kB
dist/build/skew-protection.js 4.1 kB / 1.3 kB
dist/build/templates/handler-monorepo.tmpl.js 1.6 kB / 648 B
dist/build/templates/handler.tmpl.js 1.5 kB / 601 B
dist/build/verification.js 4.5 kB / 1.6 kB
dist/esm-chunks/chunk-6BT4RYQJ.js 1.9 kB / 862 B
dist/esm-chunks/chunk-JNOKXHJS.js 63.1 kB / 11.3 kB
dist/esm-chunks/chunk-QCOH52QC.js 27.0 kB / 5.4 kB
dist/esm-chunks/chunk-YUXQHOYO.js 187.9 kB / 33.2 kB
dist/index.js 4.1 kB / 1.2 kB
dist/run/config.js 1.4 kB / 654 B
dist/run/constants.js 526 B / 319 B
dist/run/handlers/cache.cjs 16.5 kB / 4.0 kB
dist/run/handlers/request-context.cjs 5.3 kB / 1.7 kB
dist/run/handlers/tags-handler.cjs 8.9 kB / 2.8 kB
dist/run/handlers/tracer.cjs 29.1 kB / 6.1 kB
dist/run/handlers/use-cache-handler.js 48.8 kB / 10.9 kB
dist/run/handlers/wait-until.cjs 1.4 kB / 679 B
dist/run/headers.js 8.2 kB / 2.6 kB
dist/run/next.cjs 23.8 kB / 6.0 kB
dist/run/storage/regional-blob-store.cjs 28.2 kB / 7.4 kB
dist/run/storage/request-scoped-in-memory-cache.cjs 48.6 kB / 11.2 kB
dist/run/storage/storage.cjs 4.8 kB / 1.5 kB
dist/shared/blob-types.cjs 1.6 kB / 648 B
dist/shared/blobkey.js 742 B / 400 B
dist/shared/cache-types.cjs 1.3 kB / 566 B
edge-runtime/lib/cjs.ts 10.7 kB / 3.1 kB
edge-runtime/lib/headers.ts 1.9 kB / 841 B
edge-runtime/lib/logging.ts 115 B / 121 B
edge-runtime/lib/middleware.ts 3.6 kB / 1.4 kB
edge-runtime/lib/next-request.ts 3.3 kB / 1.1 kB
edge-runtime/lib/response.ts 10.0 kB / 3.0 kB
edge-runtime/lib/routing.ts 15.3 kB / 4.0 kB
edge-runtime/lib/util.ts 3.7 kB / 1.3 kB
edge-runtime/matchers.json 3 B / 23 B
edge-runtime/middleware.ts 2.4 kB / 1.0 kB
edge-runtime/next.config.json 3 B / 23 B
edge-runtime/README.md 992 B / 509 B
edge-runtime/shim/edge.js 1.6 kB / 788 B
edge-runtime/shim/node.js 766 B / 397 B
edge-runtime/vendor.ts 1.1 kB / 360 B
edge-runtime/vendor/deno.land/std@0.175.0/_util/asserts.ts 854 B / 461 B
edge-runtime/vendor/deno.land/std@0.175.0/_util/os.ts 644 B / 355 B
edge-runtime/vendor/deno.land/std@0.175.0/async/abortable.ts 4.0 kB / 1.0 kB
edge-runtime/vendor/deno.land/std@0.175.0/async/deadline.ts 974 B / 544 B
edge-runtime/vendor/deno.land/std@0.175.0/async/debounce.ts 2.2 kB / 956 B
edge-runtime/vendor/deno.land/std@0.175.0/async/deferred.ts 1.5 kB / 798 B
edge-runtime/vendor/deno.land/std@0.175.0/async/delay.ts 1.8 kB / 845 B
edge-runtime/vendor/deno.land/std@0.175.0/async/mod.ts 465 B / 241 B
edge-runtime/vendor/deno.land/std@0.175.0/async/mux_async_iterator.ts 2.5 kB / 1.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/async/pool.ts 3.2 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/async/retry.ts 2.4 kB / 1.0 kB
edge-runtime/vendor/deno.land/std@0.175.0/async/tee.ts 2.1 kB / 924 B
edge-runtime/vendor/deno.land/std@0.175.0/bytes/index_of_needle.ts 1.4 kB / 668 B
edge-runtime/vendor/deno.land/std@0.175.0/crypto/timing_safe_equal.ts 875 B / 442 B
edge-runtime/vendor/deno.land/std@0.175.0/datetime/to_imf.ts 1.3 kB / 681 B
edge-runtime/vendor/deno.land/std@0.175.0/encoding/base64.ts 2.5 kB / 1.0 kB
edge-runtime/vendor/deno.land/std@0.175.0/encoding/base64url.ts 2.0 kB / 872 B
edge-runtime/vendor/deno.land/std@0.175.0/flags/mod.ts 22.6 kB / 5.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/fmt/colors.ts 12.4 kB / 2.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/fmt/printf.ts 27.7 kB / 7.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/http/cookie.ts 11.5 kB / 3.6 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_core.ts 2.3 kB / 716 B
edge-runtime/vendor/deno.land/std@0.175.0/node/_events.d.ts 27.2 kB / 5.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_events.mjs 28.0 kB / 7.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_global.d.ts 1.7 kB / 650 B
edge-runtime/vendor/deno.land/std@0.175.0/node/_next_tick.ts 5.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_process/exiting.ts 138 B / 138 B
edge-runtime/vendor/deno.land/std@0.175.0/node/_process/process.ts 3.8 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_process/stdio.mjs 336 B / 233 B
edge-runtime/vendor/deno.land/std@0.175.0/node/_process/streams.mjs 4.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_stream.d.ts 53.2 kB / 11.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_stream.mjs 91.2 kB / 25.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_util/_util_callbackify.ts 4.3 kB / 1.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/_utils.ts 5.9 kB / 2.0 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/assert.ts 23.1 kB / 4.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/assertion_error.ts 19.6 kB / 6.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/async_hooks.ts 7.7 kB / 2.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/buffer.ts 262 B / 204 B
edge-runtime/vendor/deno.land/std@0.175.0/node/events.ts 303 B / 221 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/_libuv_winerror.ts 7.8 kB / 1.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/_listen.ts 561 B / 342 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/_node.ts 443 B / 335 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/_utils.ts 2.4 kB / 938 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/_winerror.ts 354.4 kB / 64.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/#_timingsafeequal_bd5c8.ts 479 B / 268 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/ares.ts 2.4 kB / 1.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/async_wrap.ts 4.0 kB / 1.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/buffer.ts 3.5 kB / 1.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/cares_wrap.ts 15.2 kB / 3.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/config.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/connection_wrap.ts 2.6 kB / 1.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/constants.ts 21.5 kB / 5.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/contextify.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/credentials.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/crypto.ts 448 B / 244 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/errors.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/fs_dir.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/fs_event_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/fs.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/handle_wrap.ts 1.8 kB / 1.0 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/heap_utils.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/http_parser.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/icu.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/inspector.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/js_stream.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/messaging.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/mod.ts 3.1 kB / 955 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/module_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/native_module.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/natives.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/node_file.ts 2.9 kB / 1.5 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/node_options.ts 1.8 kB / 989 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/options.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/os.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/performance.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/pipe_wrap.ts 10.4 kB / 3.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/process_methods.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/report.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/serdes.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/signal_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/spawn_sync.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/stream_wrap.ts 9.3 kB / 2.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/string_decoder.ts 504 B / 261 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/symbols.ts 1.4 kB / 828 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/task_queue.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/tcp_wrap.ts 13.1 kB / 3.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/timers.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/tls_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/trace_events.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/tty_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/types.ts 5.7 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/udp_wrap.ts 12.4 kB / 3.6 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/url.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/util.ts 4.0 kB / 1.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/uv.ts 20.1 kB / 3.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/v8.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/worker.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal_binding/zlib.ts 87 B / 104 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/buffer.d.ts 73.6 kB / 12.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/buffer.mjs 66.1 kB / 10.6 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/crypto/_keys.ts 463 B / 262 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/crypto/constants.ts 252 B / 173 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/error_codes.ts 322 B / 250 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/errors.ts 78.9 kB / 17.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/fixed_queue.ts 4.4 kB / 1.2 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/hide_stack_frames.ts 550 B / 377 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/net.ts 3.1 kB / 1.5 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/normalize_encoding.mjs 2.1 kB / 500 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/options.ts 1.7 kB / 959 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/primordials.mjs 1.8 kB / 431 B
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/process/per_thread.mjs 7.8 kB / 2.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/readline/callbacks.mjs 3.8 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/readline/utils.mjs 14.3 kB / 3.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/streams/destroy.mjs 6.9 kB / 1.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/streams/end-of-stream.mjs 7.1 kB / 1.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/streams/utils.mjs 5.9 kB / 1.2 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/util.mjs 4.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/util/comparisons.ts 16.6 kB / 3.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/util/debuglog.ts 3.2 kB / 1.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/util/inspect.mjs 71.5 kB / 19.8 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/util/types.ts 3.7 kB / 1.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/internal/validators.mjs 8.0 kB / 2.1 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/process.ts 19.4 kB / 5.2 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/stream.ts 671 B / 346 B
edge-runtime/vendor/deno.land/std@0.175.0/node/string_decoder.ts 10.3 kB / 3.3 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/util.ts 7.8 kB / 2.2 kB
edge-runtime/vendor/deno.land/std@0.175.0/node/util/types.ts 199 B / 153 B
edge-runtime/vendor/deno.land/std@0.175.0/path/_constants.ts 2.0 kB / 727 B
edge-runtime/vendor/deno.land/std@0.175.0/path/_interface.ts 728 B / 369 B
edge-runtime/vendor/deno.land/std@0.175.0/path/_util.ts 5.0 kB / 1.6 kB
edge-runtime/vendor/deno.land/std@0.175.0/path/common.ts 1.2 kB / 607 B
edge-runtime/vendor/deno.land/std@0.175.0/path/glob.ts 12.7 kB / 3.9 kB
edge-runtime/vendor/deno.land/std@0.175.0/path/mod.ts 1.4 kB / 690 B
edge-runtime/vendor/deno.land/std@0.175.0/path/posix.ts 13.9 kB / 3.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/path/separator.ts 259 B / 209 B
edge-runtime/vendor/deno.land/std@0.175.0/path/win32.ts 28.5 kB / 6.4 kB
edge-runtime/vendor/deno.land/std@0.175.0/streams/write_all.ts 2.2 kB / 598 B
edge-runtime/vendor/deno.land/std@0.175.0/testing/_diff.ts 11.6 kB / 3.6 kB
edge-runtime/vendor/deno.land/std@0.175.0/testing/_format.ts 705 B / 462 B
edge-runtime/vendor/deno.land/std@0.175.0/testing/asserts.ts 25.5 kB / 5.7 kB
edge-runtime/vendor/deno.land/std@0.175.0/types.d.ts 4.2 kB / 1.2 kB
edge-runtime/vendor/deno.land/x/htmlrewriter@v1.0.0/pkg/htmlrewriter_bg.wasm 573.2 kB / 262.7 kB
edge-runtime/vendor/deno.land/x/htmlrewriter@v1.0.0/pkg/htmlrewriter.js 31.0 kB / 4.7 kB
edge-runtime/vendor/deno.land/x/htmlrewriter@v1.0.0/src/index.ts 2.6 kB / 989 B
edge-runtime/vendor/deno.land/x/htmlrewriter@v1.0.0/src/types.d.ts 2.1 kB / 446 B
edge-runtime/vendor/deno.land/x/path_to_regexp@v6.2.1/index.ts 15.4 kB / 4.2 kB
edge-runtime/vendor/manifest.json 104 B / 119 B
edge-runtime/vendor/v1-7-0--edge-utils.netlify.app/logger/logger.ts 3.2 kB / 747 B
edge-runtime/vendor/v1-7-0--edge-utils.netlify.app/logger/mod.ts 29 B / 49 B
LICENSE 1.1 kB / 661 B
manifest.yml 31 B / 51 B
package.json 3.5 kB / 1.2 kB
README.md 2.8 kB / 1.2 kB

🤖 This report was automatically generated by pkg-size-action

@pieh pieh force-pushed the michalpiechowiak/frb-2057-malformed-next-redirect-url branch 3 times, most recently from d8090ff to 152e581 Compare December 17, 2025 19:04
@pieh pieh force-pushed the michalpiechowiak/frb-2057-malformed-next-redirect-url branch from 152e581 to 81dd0ce Compare December 17, 2025 19:31
@pieh pieh marked this pull request as ready for review December 18, 2025 09:03
@pieh pieh requested a review from a team as a code owner December 18, 2025 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test all versions Run e2e tests against old and canary versions of Next.js

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant