From 832a8a16629f2e5883db798a1b740dc0963159e1 Mon Sep 17 00:00:00 2001 From: Jonas Dittrich Date: Tue, 27 Jan 2026 22:32:21 +0100 Subject: [PATCH] fix: handle immutable headers returned by native fetch in middleware --- packages/nextjs/src/middleware/middleware.test.ts | 15 +++++++++------ packages/nextjs/src/middleware/middleware.ts | 8 +++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/nextjs/src/middleware/middleware.test.ts b/packages/nextjs/src/middleware/middleware.test.ts index 39576a74f..e7b53a4c1 100644 --- a/packages/nextjs/src/middleware/middleware.test.ts +++ b/packages/nextjs/src/middleware/middleware.test.ts @@ -43,12 +43,15 @@ const createMockRequest = ( } const mockFetch = (responseInit: Partial) => { - global.fetch = jest.fn().mockResolvedValue( - new Response(responseInit.body || "", { - headers: new Headers(responseInit.headers || {}), - status: responseInit.status || 200, - }), - ) + const response = new Response(responseInit.body || "", { + headers: new Headers(responseInit.headers || {}), + status: responseInit.status || 200, + }) + // simulate immutable headers like those returned by undici's fetch + Object.defineProperty(response.headers, "append", { value: null }) + Object.defineProperty(response.headers, "set", { value: null }) + Object.defineProperty(response.headers, "delete", { value: null }) + global.fetch = jest.fn().mockResolvedValue(response) } const createOptions = (): OryMiddlewareOptions => ({ diff --git a/packages/nextjs/src/middleware/middleware.ts b/packages/nextjs/src/middleware/middleware.ts index 4c48f3d6b..8524e6232 100644 --- a/packages/nextjs/src/middleware/middleware.ts +++ b/packages/nextjs/src/middleware/middleware.ts @@ -84,7 +84,7 @@ export async function proxyRequest( upstreamRequestHeaders.set("Ory-No-Custom-Domain-Redirect", "true") // Fetch the upstream response - const upstreamResponse = await fetch(upstreamUrl.toString(), { + let upstreamResponse = await fetch(upstreamUrl.toString(), { method: request.method, headers: upstreamRequestHeaders, body: @@ -93,6 +93,12 @@ export async function proxyRequest( : null, redirect: "manual", }) + upstreamResponse = new Response(upstreamResponse.body, { + status: upstreamResponse.status, + statusText: upstreamResponse.statusText, + // response may have immutable headers + headers: new Headers(upstreamResponse.headers), + }) // Delete headers that should not be forwarded defaultOmitHeaders.forEach((header) => {