Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

unixTerminal: input is silently queued forever when libuv threadpool completions stop arriving (CustomWriteStream has no watchdog)

Open
#939 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@nireak is already working on this.

Since Aug 18, 2026.

  • #956 by @nireak — open

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
electron, node.js, typescript
Domain
cli

Research direction

Start at CustomWriteStream.write() and _processWriteQueue(), focusing on how fs.write completion advances the queue. Run the FIFO-based deterministic reproduction and inspect the queue behavior when threadpool callbacks stop arriving. Done should include a defined recovery or failure signal for stalled input, backed by a regression test.

Written by the indexing model from the issue text.

Description

Environment

  • node-pty 1.1.0 (CustomWriteStream write path from #833)
  • Electron app (pty host runs in a utility process), macOS 15 / darwin arm64

Issue

CustomWriteStream.write() queues data and relies on the async fs.write completion callback to advance the queue:

  • write() only starts processing when the queue transitions 0 → 1
  • _processWriteQueue() issues one fs.write and continues from its callback

fs.write completes on the libuv threadpool. If the pool stops delivering completions — which we observed live in production: all 4 workers idle in pthread_cond_wait, submitted work never picked up, event loop perfectly healthy — the callback never fires, the queue head never advances, and every subsequent write() appends to the queue forever. There is no error, no timeout, and no log: from the embedder's perspective the terminal simply stops accepting input while output (event-loop reads) keeps flowing. Terminal.write() returns void, so the embedder cannot observe or mitigate this from outside.

We confirmed this mechanism while investigating Orca's long-running "terminal intermittently stops accepting input" issue (stablyai/orca#8104). In the live wedged process, _writeQueue held every lost keystroke with the first task still at offset: 0, and hot-patching write to fs.writeSync restored input instantly — the fd was fine, only the threadpool path was dead.

We're investigating the Electron/libuv threadpool wedge separately. This issue is about how node-pty behaves when it happens: input stays queued indefinitely with no error and no recovery path.

Deterministic repro

The wedge can be simulated exactly by pinning every threadpool worker with a FIFO reader-open (blocks in open() until a writer appears):

const fs = require('fs');
const pty = require('node-pty');
const { execFileSync } = require('child_process');

execFileSync('mkfifo', ['/tmp/stall.fifo']);
const p = pty.spawn('/bin/sh', ['-c', 'read line; echo "GOT:$line"'], {});
p.onData((d) => process.stdout.write(d));

setTimeout(() => {
  for (let i = 0; i < 6; i++) fs.open('/tmp/stall.fifo', 'r', () => {});
  setTimeout(() => {
    p.write('hello\n');           // never reaches the shell
    fs.stat('/tmp', () => console.log('pool alive')); // never prints
  }, 300);
}, 300);
Dominant language
TypeScript
Stars
2k
Forks
341
Avg merge
13h 17m
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/node-pty

All issues in microsoft/node-pty

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.