Skip to content

Promise never resolves if process output pipes are read first in node 18.14.0 #516

@anomiex

Description

@anomiex

Consider this code:

import { execa } from 'execa';
import readline from 'node:readline';

const proc = execa( 'find', [ '/usr/bin', '-type', 'f' ], { stdio: [ 'ignore', 'pipe', 'inherit' ] } );

const rl = readline.createInterface( {
	input: proc.stdout,
	crlfDelay: Infinity,
} );

let ct = 0;
for await ( const l of rl ) {
	ct++;
}
console.log( `Saw ${ct} files` );

const result = await proc;
console.log( `Process exit code: ${result.exitCode}` );

When run with execa 6.1.0 and node 18.14.0, node will exit without ever finishing the await, presumably due to the event loop becoming empty.

This seems to be something of the opposite of the caution that's already in the documentation for the buffer option:

When set to false, you must read the output of stdout and stderr (or all if the all option is true). Otherwise the returned promise will not be resolved/rejected.

Apparently starting with node 18.14.0 the converse is also true: if you're going to read the output of stdout or stderr (or all) yourself then you need to set buffer: false or the returned promise will not be resolved/rejected.

I don't know if there's a way around this (maybe you could check if the streams' readableEnded is true before trying to create promises for them? Or create the buffer streams before returning from execa()?) or if this behavior change in node is itself a bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions