remix icon indicating copy to clipboard operation
remix copied to clipboard

Piping `res.body` to TransformStream throws an error

Open grabbou opened this issue 2 years ago • 7 comments

What version of Remix are you using?

Latest

Are all your remix dependencies & dev-dependencies using the same version?

  • [X] Yes

Steps to Reproduce

  1. Fetch any URL
  2. PipeThrough res.body into TransformStream

Expected Behavior

Fetching and piping through the stream to TransformStream works without issues.

Actual Behavior

You will receive an error from Web polyfill used by Remix that "first parameter" (in this case, TransformStream) has a readable property that is not a ReadableStream.

First parameter has member 'readable' that is not a ReadableStream.

This is because TransformStream is not polyfilled along ReadableStream/WritableStream, as a result, native Node implementation is loaded.

When there are both polyfill and native streams circling around, this can lead to issues, e.g: https://github.com/MattiasBuelens/web-streams-polyfill/issues/93#issuecomment-925329286

grabbou avatar Jun 18 '23 17:06 grabbou

I found that when I polyfill TransformStream in injectGlobals or in server.ts, it still does not work:

import { installGlobals } from '@remix-run/node'
import { TransformStream } from '@remix-run/web-stream'

installGlobals()

global.TransformStream = TransformStream

But when I patch the source code directly, it works:

diff --git a/node_modules/ai/dist/index.js b/node_modules/ai/dist/index.js
index 46dcb84..b608338 100644
--- a/node_modules/ai/dist/index.js
+++ b/node_modules/ai/dist/index.js
@@ -70,6 +70,8 @@ __export(streams_exports, {
 });
 module.exports = __toCommonJS(streams_exports);
 
+const { Response } = require("@remix-run/node");
+const { TransformStream, ReadableStream } = require("@remix-run/web-stream");
 // streams/ai-stream.ts
 var import_eventsource_parser = require("eventsource-parser");
 function createEventStreamTransformer(customParser) {

Note I also have to import Response and ReadableStream explicitly from Remix packages, otherwise, it doesn't work while deployed in the Vercel environment.

grabbou avatar Jun 18 '23 17:06 grabbou

Any updates? Still facing this when using Remix with Vercel AI SDK 3.1

wong2 avatar Jun 02 '24 10:06 wong2

I have encountered the same problem. The description provides a good explanation, but I would like to add some information for users who are struggling like me.

As mentioned, this is an issue with the polyfill. For example, the following code does not work when using fetch from @remix-run/web-fetch:

const { fetch } = require("@remix-run/web-fetch");
(async () => {
  const res = await fetch("https://remix.run");
  res.body.pipeThrough(new TextDecoderStream()).getReader()
  // this throws:
  //   Uncaught TypeError: First parameter has member 'readable' that is not a ReadableStream.
})();

installGlobals from @remix-run/node installs this fetch globally. While this is necessary for compatibility, it also brings issues using pipeThrough(TransformStream) As a result, it can appear to cause errors in external libraries that use fetch.

If you are using Node 20 or later as a runtime, you can avoid this issue by using the native fetch. Removing installGlobals() or replacing it with installGlobals({ nativeFetch: true }).

There are several issues that I suspect might be caused by this problem:

  • https://github.com/remix-run/remix/issues/7547
  • https://github.com/remix-run/remix/issues/7614
  • https://github.com/remix-run/remix/issues/9285

According to these comments, the fetch polyfill will likely be discontinued in the next major version of Remix.

  • https://github.com/remix-run/remix/blob/main/CHANGELOG.md#v290
  • https://github.com/remix-run/remix/pull/9198

pokutuna avatar Jun 03 '24 00:06 pokutuna

@pokutuna I tried your solution, nativeFetch: true works in dev mode, but doesn't work after deploy with remix vite:build && remix-serve ./build/server/index.js. Do you have a solution?

wong2 avatar Jun 03 '24 12:06 wong2

@wong2 I encountered a similar issue. It seems that installGlobals does not have an effect when using remix-serve.

For preparation of using Node's built in fetch implementation, installing the fetch globals is now a responsibility of the app server. If you are using remix-serve, nothing is required. If you are using your own app server, you will need to install the globals yourself. https://remix.run/docs/en/main/start/v2#installglobals

Although it is unstable, you can avoid this issue by enabling single fetch. Since single fetch is being migrated to turbo-stream, it should resolve issues related to web-fetch and web-streams-polyfill.

amaany3 avatar Jun 03 '24 23:06 amaany3

@amaany3 Thanks! I also found after enable single fetch it works!

wong2 avatar Jun 04 '24 01:06 wong2

Sorry for the confusion. I was talking about transforming streams.

Thank you for the follow-up. @amaany3

pokutuna avatar Jun 04 '24 04:06 pokutuna

Thank you for opening this issue, and our apologies we haven't gotten around to it yet!

With the release of React Router v7 we are sun-setting continued development/maintenance on Remix v2. If you have not already upgraded to React Router v7, we recommend you do so. We've tried to make the upgrade process as smooth as possible with our Future Flags. We are now in the process of cleaning up outdated issues and pull requests to improve the overall hygiene of our repositories.

We plan to continue to address 2 types of issues in Remix v2:

  • Bugs that pose security concerns
  • Bugs that prevent upgrading to React Router v7

If you believe this issue meets one of those criteria, please respond or create a new issue.

For all other issues, ongoing maintenance will be happening in React Router v7, so:

  • If this is a bug, please reopen this issue in that repo with a new minimal reproduction against v7
  • If this is a feature request, please open a new Proposal Discussion in React Router, and if it gets enough community support it can be considered for implementation

If you have any questions you can always reach out on Discord. Thanks again for providing feedback and helping us make our framework even better!

brophdawg11 avatar May 01 '25 20:05 brophdawg11