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
Shared WebSocket RPC sessions in workerd seem to fail under large payload volume #158
While working on a new feature that uses remote bindings to populate OpenNext cache entries into R2, we noticed that a shared WebSocket RPC session could fall over in workerd under large payload volume. I'm not confident whether the right fix belongs in capnweb or in workerd, but it seems to point more at the shared WebSocket session path than anything higher-level.
What seems to be happening is:
a long-lived shared WebSocket RPC session works fine in Node
the same pattern does not hold up in workerd once the payloads get large enough
if we avoid reusing one long-lived session and instead use fresh sessions in smaller batches, the problem goes away
I put together a repro in #157. In the failing test, workerd eventually OOMs and the client side ends with fetch failed / ECONNREFUSED:
workerd/jsg/setup.c++:38: fatal: V8 fatal error; location = Ineffective mark-compacts near heap limit; message = : allocation failed: JavaScript heap out of memory
It suggests the issue to be most likely in the shared WebSocket session path, specifically around backpressure / in-flight data handling. As it doesn’t see any obvious transport-level flow control in the WebSocketTransport:
Opus 4.7 analyzed this and concluded it's actually due to the Promise.race() memory leak fixed by #154. Apparently, the leak actually leaks not just promise nodes but the entire received messages. OMG.
The reason it works on Node and not workerd is only because Node doesn't use pointer compression and as such is able to reach larger heap sizes. If you make the test run longer it should eventually crash Node too.
my reading of the above is that this can now be closed now that #154 (and #168) are closed. if that's not right please let me know and we can reopen and investigate :)
Activity
kentonv commentedon Mar 20, 2026
Have you tried asking an AI to analyze the issue? What did it say?
edmundhung commentedon Mar 20, 2026
It suggests the issue to be most likely in the shared WebSocket session path, specifically around backpressure / in-flight data handling. As it doesn’t see any obvious transport-level flow control in the
WebSocketTransport:capnweb/src/websocket.ts
Lines 41 to 57 in cfa1b95
I did notice there's already flow-control / backpressure logic around streams, so I wonder if the WebSocket transport might need something similar?
kentonv commentedon Apr 17, 2026
Opus 4.7 analyzed this and concluded it's actually due to the Promise.race() memory leak fixed by #154. Apparently, the leak actually leaks not just promise nodes but the entire received messages. OMG.
O.
M.
G.
https://x.com/KentonVarda/status/2044935325554823193
kentonv commentedon Apr 17, 2026
The reason it works on Node and not workerd is only because Node doesn't use pointer compression and as such is able to reach larger heap sizes. If you make the test run longer it should eventually crash Node too.
dimitropoulos commentedon May 22, 2026
my reading of the above is that this can now be closed now that #154 (and #168) are closed. if that's not right please let me know and we can reopen and investigate :)