-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React 18: "The stream is not in a state that permits close" in renderToReadableStream
#22772
Comments
Have you looked at what chain of assumptions leads to this? It seems like it would be good to understand what different state machines are involved and why something's happening in CF that doesn't happen in the browser. |
pipeToReadableStream
renderToReadableStream
@gaearon after lots of digging, here's what we've discovered: The difference between Cloudflare/Oxygen Workers runtimes and the browser comes down to how the In the browser and related fizz tests, this is how the stream (via await response.blob(); This presumably results in a single In the worker runtime, for await (const chunk of response.body) {
// write chunk from server
} Importantly, this results in When combined with Suspense boundaries, This results in the following error on the server:
You can also reproduce this directly in the browser by attempting to read the stream with If this seems like a legitimate bug to you, a couple ideas I had:
Here are some other resources and scratch notes: jplhomer/vite-streaming-ssr-demo#1 (comment) |
RE: "The stream is not in a state that permits close" in `renderToReadableStream` facebook#22772
On a second thought this should probably fix it. I think I finally understand how it's supposed to work now. #23342 |
I removed the equivalency of this in facebook#22446. However, I didn't fully understand the intended semantics of the spec but I understand this better. I believe this fixes facebook#22772. This includes the test from facebook#22889 but should ideally have one for Fizz.
I removed the equivalency of this in facebook#22446. However, I didn't fully understand the intended semantics of the spec but I understand this better now. The spec is not actually recursive. It won't call pull again inside of a pull. It might not call it inside startWork neither which the original issue avoided. However, it will call pull if you enqueue to the controller without filling up the desired size outside any call. We could avoid that by returning a Promise from pull that we wait to resolve until we've performed all our pending tasks. That would be the more idiomatic solution. That's a bit more involved but since we know understand it, we can readd the reentrancy hack since we have an easy place to detect it. If anything, it should probably throw or log here otherwise. I believe this fixes facebook#22772. This includes the test from facebook#22889 but should ideally have one for Fizz.
* tests: add failing test to demonstrate bug in ReadableStream implementation * Re-add reentrancy avoidance I removed the equivalency of this in #22446. However, I didn't fully understand the intended semantics of the spec but I understand this better now. The spec is not actually recursive. It won't call pull again inside of a pull. It might not call it inside startWork neither which the original issue avoided. However, it will call pull if you enqueue to the controller without filling up the desired size outside any call. We could avoid that by returning a Promise from pull that we wait to resolve until we've performed all our pending tasks. That would be the more idiomatic solution. That's a bit more involved but since we know understand it, we can readd the reentrancy hack since we have an easy place to detect it. If anything, it should probably throw or log here otherwise. I believe this fixes #22772. This includes the test from #22889 but should ideally have one for Fizz. Co-authored-by: Josh Larson <josh.larson@shopify.com>
@jplhomer Please take another look and see if this fixes all the issues you've noticed. |
@sebmarkbage works like a charm! Thanks for taking the time to look at it and get it fixed 🎉 |
* tests: add failing test to demonstrate bug in ReadableStream implementation * Re-add reentrancy avoidance I removed the equivalency of this in facebook#22446. However, I didn't fully understand the intended semantics of the spec but I understand this better now. The spec is not actually recursive. It won't call pull again inside of a pull. It might not call it inside startWork neither which the original issue avoided. However, it will call pull if you enqueue to the controller without filling up the desired size outside any call. We could avoid that by returning a Promise from pull that we wait to resolve until we've performed all our pending tasks. That would be the more idiomatic solution. That's a bit more involved but since we know understand it, we can readd the reentrancy hack since we have an easy place to detect it. If anything, it should probably throw or log here otherwise. I believe this fixes facebook#22772. This includes the test from facebook#22889 but should ideally have one for Fizz. Co-authored-by: Josh Larson <josh.larson@shopify.com>
When using
renderToReadableStream
for e.g. Cloudflare Workers runtimes, I'm noticing this error on the server:I'm assuming this results in the following malformed chunk being sent to the stream:
Which results in the client failing:
I put together a reproduction here, powered by Miniflare for the Workers runtime: https://github.com/jplhomer/vite-streaming-ssr-demo
Possible issues
web-streams-polyfill
?The text was updated successfully, but these errors were encountered: