You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Compression middleware changes behavior of undefined statusText in writeHead #254
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.
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
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.
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:
typeof undefined !== 'string', so headerIndex = 1
headers = arguments[1] → undefined
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.
Activity
Siretu commentedon Sep 5, 2025
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.fix: resolve expressjs#254 - preserve headers set via writeHead
fix: preserve writeHead statusText and headers when compression is ac…
fix: handle undefined statusText in writeHead arguments
mahmoodhamdi commentedon Mar 29, 2026
I traced this bug to the
on-headerspackage, which is used by compression to hook intowriteHead. The issue is inon-headers'ssetWriteHeadHeadersfunction — it determines the header index based only on whetherarguments[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:typeof undefined !== 'string', soheaderIndex = 1headers = arguments[1]→undefinedarguments[2]are never readNative Node.js
writeHeadhandles 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.