Skip to content

Cloning Response change default aborting behavior #4799

@afoures

Description

@afoures

Bug Description

When using an AbortSignal with fetch, and aborting it right before reading the body via text()/json()/..., it throws an abort error, as expected.

But if the response was cloned, then it does not throw an abort error but a TypeError, like if the body was read by someone.

Reproducible By

async function test() {
  try {
    const controller = new AbortController();
    const response = await fetch("https://example.com/data", {
      signal: controller.signal,
    });
    const cloned_response = response.clone();
    controller.abort();
    // body is now used in the original response
    console.log("response.bodyUsed", response.bodyUsed);
    console.log("cloned_response.bodyUsed", cloned_response.bodyUsed);
    // throws "Body is unusable: Body has already been read"
    // but it should only throw an AbortError
    await response.text();
  } catch (error) {
    console.error(error);
  }

  console.log("--------------------------------");

  // this works as expected
  try {
    const controller = new AbortController();
    const response = await fetch("https://example.com/data", {
      signal: controller.signal,
    });
    // const cloned_response = response.clone();
    controller.abort();
    // throws AbortError as expected
    await response.text();
  } catch (error) {
    console.error(error);
  }
}

test();
response.bodyUsed true
cloned_response.bodyUsed false
TypeError: Body is unusable: Body has already been read
    at consumeBody (node:internal/deps/undici/undici:6873:31)
    at _Response.text (node:internal/deps/undici/undici:6821:18)
    at test (file:///.../reproduction.js:14:20)
    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
--------------------------------
DOMException [AbortError]: The operation was aborted.
    at new DOMException (node:internal/per_context/domexception:76:18)
    at consumeBody (node:internal/deps/undici/undici:6876:31)
    at _Response.text (node:internal/deps/undici/undici:6821:18)
    at test (file:///.../reproduction.js:31:20)
    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)

Expected Behavior

I expected it to throw an AbortError, exactly like the example without a cloned response.

Environment

macOS 15.6.1
node 24.13.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions