fetch with a streamed body (duplex: "half") hangs or ends cleanly with a truncated body when the response stream errors · Issue #46219 · oven-sh/bun · GitHub
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
fetch with a streamed body (duplex: "half") hangs or ends cleanly with a truncated body when the response stream errors #46219
Darwin 27.0.1 arm64 (the same test also fails intermittently on GitHub's ubuntu-latest runners)
What steps can reproduce the bug?
A server echoes a streamed request body through a TransformStream that errors once more than LIMIT bytes have
passed. A client streams LIMIT + 1 bytes with fetch(url, { method: "POST", body: ReadableStream, duplex: "half" })
and reads the response body.
server.ts:
constLIMIT=Number(process.env.LIMIT??128*1024*1024);constserver=Bun.serve({port: 0,fetch(req){letseen=0;returnnewResponse(req.body!.pipeThrough(newTransformStream<Uint8Array,Uint8Array>({transform(chunk,c){seen+=chunk.byteLength;if(seen>LIMIT)c.error(newError("Request body too large"));elsec.enqueue(chunk);},}),),);},});console.log(server.port);
client.ts (run as bun client.ts http://127.0.0.1:<port>/ <LIMIT + 1>):
Run the client repeatedly against one server, with nothing else loading the machine.
What is the expected behavior?
The response body breaks: the for await (or the fetch) rejects, so the client prints -1, every time.
What do you see instead?
Two wrong outcomes, intermittently:
LIMIT
tries
rejects (-1)
hangs (no end after 20 s)
ends cleanly with a truncated body
3 000 000
30
21
9
0
128 MiB
30
26
0
4 (e.g. 133 887 564 bytes, fewer than the limit)
Hang: the client's fetch or body read never settles; the process stays alive until killed.
Truncated clean end: the body iterator finishes normally with fewer bytes than were sent, with no error, so the
client cannot tell a cut-off answer from a complete one.
With curl as the client against the same server (head -c 3000001 /dev/zero | curl -T - -H "Transfer-Encoding: chunked" -X POST …), 20 of 20 runs fail with a connection error (exit 56, once 55) and none hang, which suggests
the server side aborts correctly and the issue is in fetch's handling of a response that aborts while a
streamed (duplex: "half") request body is still being sent.
Additional information
Under CPU load the hang is the common failure; a test that streams just past a 128 MiB limit times out there.
Activity