Bugfix: Fix #15004 by applying MDN recommended fix when proxying Response in page_loa...
authorDrew Silcock <drew.larry.harry.silcock@gmail.com>
Fri, 28 Nov 2025 21:06:17 +0000 (21:06 +0000)
committerGitHub <noreply@github.com>
Fri, 28 Nov 2025 21:06:17 +0000 (14:06 -0700)
* Apply MDN recommended fix when proxying Response to avoid TypeError.

On Node v24+, the undici library used for HTTP has a Response class with
a private element. Proxying the response therefore fails when calling
clone() as the method returned by the proxy cannot access the private
state element.

* Use more comprehensive Response proxy fix that makes linter happy.

By using Object.defineProperty(), we make the function identical to
introspection. Also, the linter didn't like the `...args`.

* Add page to test undici Response TypeError.

* Add generated changeset file.

* Apply suggestion from @elliott-with-the-longest-name-on-github

---------

Co-authored-by: Elliott Johnson <hello@ell.iott.dev>
.changeset/tangy-donkeys-knock.md [new file with mode: 0644]
packages/kit/src/runtime/server/page/load_data.js
packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.js [new file with mode: 0644]
packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.svelte [new file with mode: 0644]

diff --git a/.changeset/tangy-donkeys-knock.md b/.changeset/tangy-donkeys-knock.md
new file mode 100644 (file)
index 0000000..4464e8c
--- /dev/null
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: TypeError when doing response.clone() in page load
index 520d6ff5bb85f3f9376a7fe50870e927fd200ff4..b322bfe810cb6c5a7027acb72baaaed8aae2ff29 100644 (file)
@@ -316,7 +316,7 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
                let teed_body;
 
                const proxy = new Proxy(response, {
-                       get(response, key, _receiver) {
+                       get(response, key, receiver) {
                                /**
                                 * @param {string | undefined} body
                                 * @param {boolean} is_b64
@@ -427,7 +427,28 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
                                        };
                                }
 
-                               return Reflect.get(response, key, response);
+                               const value = Reflect.get(response, key, response);
+
+                               if (value instanceof Function) {
+                                       // On Node v24+, the Response object has a private element #state – we
+                                       // need to bind this function to the response in order to allow it to
+                                       // access this private element. Defining the name and length ensure it
+                                       // is identical to the original function when introspected.
+                                       return Object.defineProperties(
+                                               /**
+                                                * @this {any}
+                                                */
+                                               function () {
+                                                       return Reflect.apply(value, this === receiver ? response : this, arguments);
+                                               },
+                                               {
+                                                       name: { value: value.name },
+                                                       length: { value: value.length }
+                                               }
+                                       );
+                               }
+
+                               return value;
                        }
                });
 
diff --git a/packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.js b/packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.js
new file mode 100644 (file)
index 0000000..00edd88
--- /dev/null
@@ -0,0 +1,9 @@
+/** @type {import('@sveltejs/kit').Load} */
+export async function load({ url, fetch }) {
+       const href = new URL(url);
+       href.pathname = '';
+
+       const res = await fetch(href);
+       const clonedRes = res.clone();
+       return { text: await clonedRes.text() };
+}
diff --git a/packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/server-response-clone/+page.svelte
new file mode 100644 (file)
index 0000000..32fee25
--- /dev/null
@@ -0,0 +1,10 @@
+<script>
+       /** @type {import('./$types').PageData} */
+       export let data;
+</script>
+
+<h1>the text is:</h1>
+
+<p>
+       {data.text}
+</p>