Skip to content

req.signal.aborted is wrongly true when canceling body read in node #160

@pi0

Description

@pi0

Environment

  • srvx: 0.10.0
  • node v24.11.1

Reproduction

import { serve } from "srvx";

const server = serve({
  port: 3000,
  fetch: async (req) => {
    const reader = req.body.getReader();
    console.log(new TextDecoder().decode((await reader.read()).value));

    await reader.cancel();
    console.log({ abortedAfterCancel: req.signal.aborted }); // IMPORTANT

    await new Promise((resolve) => setTimeout(resolve, 100));

    console.log({ abortedAfterTimeout: req.signal.aborted, expected: false });

    return new Response("OK");
  },
});

await fetch("http://localhost:3000", {
  method: "POST",
  body: new ReadableStream({
    async pull(controller) {
      // console.log("[client] pulling");
      await new Promise((resolve) => setTimeout(resolve, 100));
      controller.enqueue(new TextEncoder().encode("hello"));
    },
  }),
  duplex: "half",
});

await server.close(true);

Describe the bug

Running reproduction in Deno and Bun, req.signal.aborted is false after timeout but in node adapter, it gets true

Additional context

Originally reported by @unnoq in h3js/h3#1275 and #157

Logs

# node repro.mjs
➜ Listening on: http://localhost:3000/ (all interfaces)
hello
{ abortedAfterCancel: false }
{ abortedAfterTimeout: true, expected: false }

$ bun repro.mjs
➜ Listening on: http://localhost:3000/ (all interfaces)
hello
{
  abortedAfterCancel: false,
}
{
  abortedAfterTimeout: false,
  expected: false,
}

$ deno -A repro.mjs
➜ Listening on: http://localhost:3000/ (all interfaces)
hello
{ abortedAfterCancel: false }
{ abortedAfterTimeout: false, expected: false }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingnode

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions