Skip to content

Uncatchable AssertionError: assert(!this.paused) on socket end #5360

Description

@andreypopp

Description

If the consumer doesn't read the body immediately, the HTTP/1 parser pauses under
backpressure. When the socket ends (FIN), onHttpSocketEnd calls parser.finish(),
which asserts !this.paused. Since the parser is paused, this throws an uncatchable
AssertionError from the socket 'end' handler and crashes the process.

AssertionError [ERR_ASSERTION]: assert(!this.paused)
    at Parser.finish (.../undici/lib/dispatcher/client-h1.js:374:5)
    at Socket.onHttpSocketEnd (.../undici/lib/dispatcher/client-h1.js:951:30)

onHttpSocketEnd doesn't check parser.paused before calling finish().

Reproduction (minimised with Claude Code)

import { createServer } from "node:net";
import { fetch } from "undici";

const BODY = Buffer.alloc(64 * 1024, 0x61);

const server = createServer((sock) => {
  sock.once("data", () => {
    sock.write(
      "HTTP/1.1 200 OK\r\n" +
        `Content-Length: ${BODY.length}\r\n` +
        "Connection: close\r\n\r\n",
    );
    sock.write(BODY);
    sock.end(); // FIN
  });
});

server.listen(0, "127.0.0.1", async () => {
  const { port } = server.address();
  const res = await fetch(`http://127.0.0.1:${port}/`);
  void res; // never read the body -> parser pauses -> crash on FIN
  await new Promise((r) => setTimeout(r, 1000));
  console.log("no crash"); // never reached
});

The 64 KiB body is the body highWaterMark — the smallest size that pauses while still
arriving in one socket read, which makes this deterministic. It's not a fixed value:
the real trigger is "paused with the read buffer drained when FIN arrives," so the
size is network-dependent (intermittent across sizes over a real connection).

Expected vs actual

  • Expected: clean end, or a catchable error. A peer closing a non-keep-alive
    response under backpressure shouldn't crash the process.
  • Actual: uncatchable AssertionError, exit code 1.

Environment

  • undici 8.3.0 (and current main)
  • Node.js v22.22.2, Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions