Skip to content
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

.pipe() and .pipeTo() fail when the source stream is constructed from a Buffer #56297

Closed
gabrielschulhof opened this issue Dec 17, 2024 · 5 comments
Labels
stream Issues and PRs related to the stream subsystem. web streams

Comments

@gabrielschulhof
Copy link
Contributor

gabrielschulhof commented Dec 17, 2024

Version

v22.9.0, v23.4.0

Platform

Darwin XXXXXXXXXX 24.2.0 Darwin Kernel Version 24.2.0: Fri Dec  6 19:01:59 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T6000 arm64

Subsystem

stream

What steps will reproduce the bug?

const path = require('node:path');
const fs = require('node:fs');
const { Readable, Writable } = require('node:stream');

const fileBuffer = fs.readFileSync(__filename);
const readable = fs.createReadStream(path.resolve(__filename));
const writable = fs.createWriteStream(`${__filename}_copy`);
const webReadable = Readable.toWeb(readable);
const webWritable = Writable.toWeb(writable);
const webReadableFromBuffer = ReadableStream.from(fileBuffer);
const readableFromBuffer = Readable.from(fileBuffer);
const readableFromWebReadableFromBuffer = Readable.from(webReadableFromBuffer);
const readableFromWebReadableFromReadable = Readable.from(webReadable);

// readable.pipe(writable);
// OK

// readableFromBuffer.pipe(writable);
// OK

// readableFromWebReadableFromReadable.pipe(writable);
// OK

// webReadable.pipeTo(webWritable);
// TypeError [ERR_INVALID_STATE]: Invalid state: The ReadableStream is locked

// webReadableFromBuffer.pipeTo(webWritable);
// TypeError [ERR_INVALID_STATE]: Invalid state: The ReadableStream is locked

// readableFromWebReadableFromBuffer.pipe(writable);
// TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received type number (60)

How often does it reproduce? Is there a required condition?

Every time. No preconditions.

What is the expected behavior? Why is that the expected behavior?

All the above combinations should succeed.

What do you see instead?

Errors in the cases where the Readable or ReadableStream is constructed from a Buffer.

Additional information

No response

@gabrielschulhof gabrielschulhof added stream Issues and PRs related to the stream subsystem. web streams labels Dec 17, 2024
@gabrielschulhof
Copy link
Contributor Author

Potentially related: #56139

@gabrielschulhof
Copy link
Contributor Author

Also potentially related: #44866

@gabrielschulhof
Copy link
Contributor Author

gabrielschulhof commented Dec 30, 2024

Creating a new stream each time solves the problem of the ReadableStream being locked:

const path = require('node:path');
const fs = require('node:fs');
const { Readable, Writable } = require('node:stream');

const fileBuffer = () => fs.readFileSync(__filename);
const readable = () => fs.createReadStream(path.resolve(__filename));
const writable = () => fs.createWriteStream(`${__filename}_copy`);
const webReadable = () => Readable.toWeb(readable());
const webWritable = () => Writable.toWeb(writable());
const webReadableFromBuffer = () => ReadableStream.from(fileBuffer());
const readableFromBuffer = () => Readable.from(fileBuffer());
const readableFromWebReadableFromBuffer = () => Readable.from(webReadableFromBuffer());

// If we don't return a new webReadable every time, the one we create gets
// locked at this point, because it is used exclusively by the Readable that
// wraps it.
const readableFromWebReadableFromReadable = () => Readable.from(webReadable());

// readable().pipe(writable());
// OK

// readableFromBuffer().pipe(writable());
// OK

// readableFromWebReadableFromReadable().pipe(writable());
// OK

// webReadable().pipeTo(webWritable());
// OK

// webReadableFromBuffer().pipeTo(webWritable());
// TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received type number (99)

// readableFromWebReadableFromBuffer().pipe(writable());
// TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received type number (99)

@gabrielschulhof
Copy link
Contributor Author

gabrielschulhof commented Dec 30, 2024

As best I can tell,

const wr = webReadableFromBuffer()
;(async () => {
for await (const chunk of wr) {
  console.log(`|${JSON.stringify(chunk, null, 2)}|`)
}
})()

outputs a sequence of numbers, whereas doing the same loop over a ReadableStream in a browser outputs a sequence of Uint8Array objects like


|{
  "0": 87,
  "1": 119,
}|
|{
  "0": 32,
  "1": 48,
  "2": 51,
}|

This may be the discrepancy.

@gabrielschulhof
Copy link
Contributor Author

OK. Need to pass a sequence of buffers to ReadableStream.from().

gabrielschulhof added a commit that referenced this issue Dec 30, 2024
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: #56297
gabrielschulhof added a commit to gabrielschulhof/node that referenced this issue Dec 30, 2024
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: nodejs#56297
gabrielschulhof added a commit to gabrielschulhof/node that referenced this issue Dec 30, 2024
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: nodejs#56297
nodejs-github-bot pushed a commit that referenced this issue Jan 1, 2025
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: #56297
PR-URL: #56415
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Ulises Gascón <[email protected]>
aduh95 pushed a commit that referenced this issue Jan 2, 2025
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: #56297
PR-URL: #56415
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Ulises Gascón <[email protected]>
aduh95 pushed a commit that referenced this issue Jan 31, 2025
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: #56297
PR-URL: #56415
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Ulises Gascón <[email protected]>
aduh95 pushed a commit that referenced this issue Feb 4, 2025
When piping a `ReadableStream` created from an `Iterable` into a
`WritableStream`, the sequence of objects in the `Iterable` must
consist of either `Buffer`s, `TypedArray`s, or `DataView`s.

Re: #56297
PR-URL: #56415
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Ulises Gascón <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stream Issues and PRs related to the stream subsystem. web streams
Projects
None yet
Development

No branches or pull requests

1 participant