Fix static files under 768KB 404ing behind express-session (worker returns ArrayBuffer) - #351
Merged
dimdenGD merged 1 commit intoJul 23, 2026
Conversation
…atic files The file worker (used for files < 768KB, enabled by default on multi-core machines where threads defaults to 1) transfers file contents as an ArrayBuffer. ultimate-express's own res.end() accepts an ArrayBuffer, so a bare app serves these files fine. But when res.end has been wrapped per-request by middleware that inspects the chunk -- express-session is the canonical case, it calls Buffer.byteLength(chunk) to set Content-Length -- the ArrayBuffer is rejected with ERR_INVALID_ARG_TYPE. The rejection lands in sendFile's .catch, which calls the static middleware's fallthrough next(), and the request ends up at the outer 404 handler. Net effect: every static file under 768KB mounted after express-session returns 404 on multi-core boxes with default settings, even though the file exists and is readable. Wrap the worker result in a Buffer (zero-copy) at the resolve boundary so readFileWithWorker returns the same type as fs.readFile, which every express-compatible end() wrapper accepts.
emilioastarita
marked this pull request as ready for review
July 23, 2026 19:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Practical impact
On any multi-core host with default settings, every static file smaller than 768KB mounted after
express-session(or any middleware that wrapsres.end, e.g. passport) returns 404, even though the file exists on disk and is readable. Statics mounted before the session middleware work, which is why this hides in development and small apps.Cause
ultimate-express defaults
threads = 1on multi-core hosts and serves files under 768KB through the file worker (response.js,sendFile). The worker transfers file contents as an ArrayBuffer (src/worker.js). ultimate-express's ownres.end()accepts an ArrayBuffer, so a bare app serves the file fine. But whenres.endhas been wrapped per-request — express-session wraps it and callsBuffer.byteLength(chunk)to setContent-Length— the ArrayBuffer is rejected:That rejection lands in
sendFile's.catch, which calls the static middleware's fallthroughnext(); the request falls through to the outer 404 handler.Repro
Fix
Wrap the worker result in a
Buffer(zero-copy) at thereadFileWithWorkerresolve boundary, so the helper returns the same type asfs.readFile— which every express-compatibleend()wrapper accepts. It is the only consumer of the worker read, and the conversion is a no-op for any already-Buffer value.Tests
New
tests/tests/middlewares/express-static-session.jswith controls: default threads + session (the bug),threads: 0+ session (pipe path), default threads without session (unwrappedendaccepts the ArrayBuffer — why it hides), and a >768KB file (stream path bypasses the worker). Fails on master, passes with the fix, output identical to express 4 and 5. Full suite passes (only the unrelatedapp-cluster.js/ port-3000 environmental failure).Context
Found integrating
@bull-board/express's sub-app on a production Express 5-style stack; verified against real express 5.2.1.