Skip to content

Compression middleware changes behavior of undefined statusText in writeHead #254

Description

@Siretu

Environment information

Version: Compression 1.8.1

Platform: MacOS 15.6

Node.js version: 22.15.1

Any other relevant information:

What steps will reproduce the bug?

  1. Setup a node server with the compression middleware. You can also set the filter method to always return false, to ensure it's not doing any compression.
  2. In the response handler, call response.writeHead(200, undefined, {'foo': 'bar'}). The status code and headers are not important. The important part is the undefined status text

Observe how the response headers are not getting set at all.
If you change the status text from undefined to any string, the headers do get set.
If you leave the undefined status text, but remove the compression middleware, the headers do get set.

I've attached a repro case showing this. Just npm install and then run the test with node pure-node-compression-test.js

compression-repro.zip

Activity

  1. added theissue type on Sep 5, 2025
  2. Siretu commented on Sep 5, 2025

    @Siretu
    Author

    Some more context on this. I figured this out after hours of chasing down a bug in our codebase. We're using the Vercel AI SDK (https://github.com/vercel/ai) and we noticed that the appropriate headers are not added unless we add a statusText to pipeUIMessageStreamToResponse.

    That method in return ends up calling into https://github.com/vercel/ai/blob/main/packages/ai/src/util/write-to-server-response.ts#L19 where it calls response.writeHead(status ?? 200, statusText, headers) which will fail if the statusText is undefined and you're using compression middleware.

  3. added a commit that references this issue on Mar 10, 2026
    a4e80f0
  4. added a commit that references this issue on Mar 24, 2026
    484e598
  5. mahmoodhamdi commented on Mar 29, 2026

    @mahmoodhamdi

    I traced this bug to the on-headers package, which is used by compression to hook into writeHead. The issue is in on-headers's setWriteHeadHeaders function — it determines the header index based only on whether arguments[1] is a string, without accounting for the case where 3 arguments are passed with a non-string second argument.

    When writeHead(200, undefined, headers) is called:

    1. typeof undefined !== 'string', so headerIndex = 1
    2. headers = arguments[1] → undefined
    3. The actual headers at arguments[2] are never read

    Native Node.js writeHead handles this correctly because it checks the total argument count.

    I've opened a fix at jshttp/on-headers#49. Once that's released, this issue should be resolved without any changes needed in compression itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions