Skip to content

ServerResponse.end() should always result in writableEnded being set to/returning true #25632

@tedmiddleton

Description

@tedmiddleton

What version of Bun is running?

1.3.0

What platform is your computer?

Darwin 24.6.0 arm64 arm

What steps can reproduce the bug?

This shows up with light-my-request and fastify - fastify preHandler hooks can send an error response but fastify doesn't detect this because reply.writableEnded isn't true the way it is at runtime. The problem seems to be because ServerResponse.end() in bun early-returns if there isn't a valid socket. Admittedly this is a weird corner-case, but the Node spec has ServerResponse writableEnded being set to true unconditionally when .end() is called. I think this is the offending code:

if (!handle) {
  if (@isCallable(callback))
    process.nextTick(callback);
  return this;  // No finished = true
}

What is the expected behavior?

ServerResponse.writableEnded should be true after ServerResponse.end() is called, no matter what.

What do you see instead?

ServerResponse.writableEnded is still false in fastify tests with preHandler hooks, fastify calls GET and POST handlers when it shouldn't (because writableEnded is false), and then fastify complains that a response has already been sent:

91 |   this.on('timeout', callback)
92 |   return this
93 | }
94 | 
95 | Response.prototype.writeHead = function () {
96 |   const result = http.ServerResponse.prototype.writeHead.apply(this, arguments)
                                                              ^
error: Cannot writeHead headers after they are sent to the client
 code: "ERR_HTTP_HEADERS_SENT"

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions