Skip to content

filehandle.readableWebStream() chunks return incompatible ArrayBuffer instead of Uint8Array #54041

@karlhorky

Description

@karlhorky

Version

v20.12.0

Platform

Linux ljysjk 6.1.43 #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

  1. Open the CodeSandbox (see code below)
  2. Observe the ERR_INVALID_ARG_TYPE error below

CodeSandbox demo: https://codesandbox.io/p/devbox/filehandle-readablewebstream-with-new-response-ljysjk?file=%2Findex.js

import fs from "node:fs/promises";
import http from "node:http";
import path from "node:path";
import { Readable } from "node:stream";

const filePath = "./image.jpg";

const server = http.createServer(async (nodeRequest, nodeResponse) => {
  const stats = await fs.stat(filePath);
  const fileHandle = await fs.open(filePath);
  const webStream = fileHandle.readableWebStream();

  nodeResponse.writeHead(200, {
    "Content-Disposition": `attachment; filename=${path.basename(filePath)}`,
    "Content-Type": "image/jpeg",
    "Content-Length": String(stats.size),
  });

  const nodeStream = Readable.fromWeb(webStream);
  nodeStream.pipe(nodeResponse);
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

Error:

Server running at http://localhost:3000/
node:events:496
      throw er; // Unhandled 'error' event
      ^

TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of ArrayBuffer
    at readableAddChunkPushByteMode (node:internal/streams/readable:480:28)
    at Readable.push (node:internal/streams/readable:390:5)
    at node:internal/webstreams/adapters:517:22
Emitted 'error' event on Readable instance at:
    at emitErrorNT (node:internal/streams/destroy:169:8)
    at emitErrorCloseNT (node:internal/streams/destroy:128:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_INVALID_ARG_TYPE'
}

Node.js v20.12.0
Failed running 'index.js'

Screenshot 2024-07-25 at 12 52 56

Alternative version with new Response():

import fs from "node:fs/promises";
import http from "node:http";
import path from "node:path";

const filePath = "./image.jpg";

const server = http.createServer(async (nodeRequest, nodeResponse) => {
  const stats = await fs.stat(filePath);
  const fileHandle = await fs.open(filePath);
  const webStream = fileHandle.readableWebStream();

  // Version with new Response()
  const webResponse = new Response(webStream, {
    status: 200,
    headers: new Headers({
      "content-disposition": `attachment; filename=${path.basename(filePath)}`,
      "content-type": "image/jpeg",
      "content-length": String(stats.size),
    }),
  });

  nodeResponse.writeHead(
    webResponse.status,
    Object.fromEntries(webResponse.headers.entries())
  );

  webResponse.body.pipeTo(
    new WritableStream({
      write(chunk) {
        nodeResponse.write(chunk);
      },
      close() {
        nodeResponse.end();
      },
    })
  );
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

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

Always

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

Web streams created by fileHandle.readableWebStream() should be compatible with Readable.fromWeb()

What do you see instead?

Web streams created by fileHandle.readableWebStream() are incompatible with Readable.fromWeb()

Additional information

Also reported over here:

cc @jasnell

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions