node-pty icon indicating copy to clipboard operation
node-pty copied to clipboard

BUG - Deadlock when using readline or inquirer before spawning a node-pty process

Open Choppel opened this issue 6 months ago • 0 comments
trafficstars

Calling readline or inquirer before spawning something via node-pty that expects some input (uses stdin) results in a deadlock.

Test files package.json

{
  "author": "",
  "dependencies": {
    "@inquirer/prompts": "^7.4.1",
    "@types/node": "^20.17.30",
    "node-pty": "^1.0.0"
  },
  "description": "",
  "keywords": [],
  "license": "ISC",
  "main": "index.js",
  "name": "test",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "type": "module",
  "version": "1.0.0"
}

index.js

import {input} from '@inquirer/prompts';
import {spawn} from 'node-pty';
import process, {stdin, stdout} from 'node:process';
import {createInterface} from 'node:readline/promises';

const callInquirer = async() => {
  await input({
    message: 'Prompt from inquirer'
  });
};

const callReadline = async() => {
  const rl = createInterface({
    input: stdin,
    output: stdout
  });

  await rl.question('Prompt from readline');

  rl.close();
};

const spawnNodePty = () => {
  const ptyProcess = spawn('bash', ['sub.sh'], {});

  process.stdin.on('data', (_data) => ptyProcess.write(_data.toString('utf-8')));

  ptyProcess.onData((_dataFromPty) => process.stdout.write(_dataFromPty));

  ptyProcess.onExit((_result) => {
    process.exit(_result.exitCode);
  });
};

const Test1 = async() => {
  // Read something from stdin via inquirer
  await callInquirer();

  // Spawn the sub.sh file
  spawnNodePty();
};

const Test2 = async() => {
  // Read something from stdin via readline
  await callReadline();

  // Spawn the sub.sh file
  spawnNodePty();
};

const Test3 = async() => {
  // Spawn the sub.sh file
  spawnNodePty();
};

await Test1(); // will deadlock at "Prompt from sub.sh" message
// OR
// await Test2(); // will deadlock at "Prompt from sub.sh" message
// OR
// await Test3(); // will NOT deadlock

sub.sh

#!/bin/bash

read -p "Prompt from sub.sh: " test

Test The three test cases can be switched by un/-commenting the individual line at the end of index.js.

I suppose the problem has something to do with the reusability of stdin.

Choppel avatar Apr 22 '25 10:04 Choppel