ITADN

Using duplex() with fd3: it must be a writable stream

#1214Openmatpen 创建于 2025-11-26
M
matpencommented
I am trying to use `execa` within a `pipeline`, which results in very elegant code. However, I am facing a problem when using an input file descriptor different from stdin. The following snippet contains a <details><summary>minimal reproducer</summary> <p> ```js // Importing dependencies import fs from 'node:fs'; import dedent from 'dedent'; import { execa } from 'execa'; import { pipeline } from 'node:stream/promises'; import { Readable } from 'node:stream'; // Run execa as duplex stream in a pipeline // The pipeline source and sink, as well as the subprocess (Python here) are not important, // instead the focus is on the "to" option for duplex() await pipeline( Readable.from('This is a test'), execa( 'python3', { input: dedent(` import os with os.fdopen(3, 'r') as file: content = json.load(file) print(content) `), stdio: ['pipe', 'pipe', 'pipe', 'pipe'], }, ).duplex({ to: 'fd3' }), process.stdout, ); ``` </p> </details> Running the code on GNU/Linux 6.14.0 with Node.js v22.15.0 and execa 9.6.0 causes the following <details><summary>error message</summary> <p> ``` file:///tmp/test/node_modules/execa/lib/arguments/fd-options.js:66 throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a writable stream, not readable.`); ^ TypeError: "to" must not be fd3. It must be a writable stream, not readable. at validateFdNumber (file:///tmp/test/node_modules/execa/lib/arguments/fd-options.js:66:9) at getFdNumber (file:///tmp/test/node_modules/execa/lib/arguments/fd-options.js:36:2) at getToStream (file:///tmp/test/node_modules/execa/lib/arguments/fd-options.js:7:19) at getSubprocessStdin (file:///tmp/test/node_modules/execa/lib/convert/writable.js:32:26) at createDuplex (file:///tmp/test/node_modules/execa/lib/convert/duplex.js:22:68) at main (file:///tmp/test/[eval1]:29:11) at file:///tmp/test/[eval1]:37:2 at ModuleJob.run (node:internal/modules/esm/module_job:274:25) at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:268:26) at async ModuleLoader.executeModuleJob (node:internal/modules/esm/loader:264:20) ``` </p> </details> I tracked the source, and noticed that by simply removing the [validation rules](https://github.com/sindresorhus/execa/blob/103095f2c9a459ae3500fa7d861f162c21a94b3a/lib/arguments/fd-options.js#L61-L67), the code runs and behaves as expected. Unfortunately, I am not familiar enough with the source code to suggest a solution, so I would appreciate any help by the maintainers or more experienced users. Thank you for a wonderful library, and its extensive documentation.
9 条评论