Skip to content

Error: process.stdout.cursorTo is not a function #546

@0xdevalias

Description

@0xdevalias

Creating a new issue to track this as #57 was incorrectly closed, and I don't have the access to re-open it as valid:


process.stdout.cursorTo is only defined when the shell you're running in isn't capturing the output. You need to check process.stdout.isTTY before trying to access it.

Source:
https://nodejs.org/api/process.html#a-note-on-process-io
https://nodejs.org/api/tty.html#writestreamcursortox-y-callback

Originally posted by @ItsHarper in #57 (comment)


process.stdout.cursorTo is only defined when the shell you're running in isn't capturing the output. You need to check process.stdout.isTTY before trying to access it.

Is it possible by any chance that you're trying to run humanify using an old node.js? It seems that stdout.cursorTo is introduced in node.js version 17, so this implies that your node.js version would have been under that.

Based on the above, we can see this behaviour in node v22, so it wasn't just an issue with running an older version of node:

⇒ node --version
v22.16.0
⇒ node -p -e "Boolean(process.stdout.isTTY)"
true

⇒ node -p -e "Boolean(process.stdout.isTTY)" | cat
false
⇒ node -p -e "process.stdout.cursorTo(0)"
true

⇒ node -p -e "process.stdout.cursorTo(0)" | cat
[eval]:1
process.stdout.cursorTo(0)
               ^

TypeError: process.stdout.cursorTo is not a function
    at [eval]:1:16
    at runScriptInThisContext (node:internal/vm:209:10)
    at node:internal/process/execution:449:12
    at [eval]-wrapper:6:24
    at runScriptInContext (node:internal/process/execution:447:60)
    at evalFunction (node:internal/process/execution:87:30)
    at evalScript (node:internal/process/execution:99:3)
    at node:internal/main/eval_string:74:3

Node.js v22.16.0

I'll fix the underlying issue in coming versions.

@jehna So this is still a valid issue that should be fixed, and this issue should be re-opened to track that.

Usage:

humanify/src/progress.ts

Lines 25 to 31 in 7beba2d

export function showPercentage(percentage: number) {
const percentageStr = Math.round(percentage * 100);
if (!verbose.enabled) {
process.stdout.clearLine?.(0);
process.stdout.cursorTo(0);
process.stdout.write(`Processing: ${percentageStr}%`);
} else {

Example of a potential fix:

export function showPercentage(percentage: number) {
  const percentageStr = Math.round(percentage * 100);

  const canUseCursorOps = process.stdout.isTTY
    && typeof process.stdout.clearLine === "function"
    && typeof process.stdout.cursorTo === "function";

  if (!verbose.enabled && canUseCursorOps) {
    process.stdout.clearLine(0);
    process.stdout.cursorTo(0);
    process.stdout.write(`Processing: ${percentageStr}%`);
  } else {
    verbose.log(`Processing: ${percentageStr}%`);
  }

  if (percentage === 1 && canUseCursorOps) {
    process.stdout.write("\n");
  }
}

Ideally a similar more explicit fix would be added to clearLine in showProgress as well, instead of just relying on the optional chaining syntax.


You can see that this would also be an issue with process.stdout.clearLine:

⇒ node -p -e "process.stdout.clearLine(0)" | cat
[eval]:1
process.stdout.clearLine(0)
               ^

TypeError: process.stdout.clearLine is not a function
    at [eval]:1:16
    at runScriptInThisContext (node:internal/vm:209:10)
    at node:internal/process/execution:449:12
    at [eval]-wrapper:6:24
    at runScriptInContext (node:internal/process/execution:447:60)
    at evalFunction (node:internal/process/execution:87:30)
    at evalScript (node:internal/process/execution:99:3)
    at node:internal/main/eval_string:74:3

Node.js v22.16.0

Except that in the code, you're calling process.stdout.clearLine with the optional chaining syntax like this:

process.stdout.clearLine?.(0);

process.stdout.clearLine?.(0);

Whereas for process.stdout.cursorTo you're not using the optional chaining syntax:

process.stdout.cursorTo(0);

Looking at the git blame / history, the progress feature seemed to be first added in 70e3196 on Aug 9, 2024, and neither used the optional chaining syntax:

But then the optional chaining was added to clearLine in 05b6a8e on Aug 9, 2024 as it broke the CI:

Originally posted by @0xdevalias in #57 (comment)

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