denoland/deno · error · ERR_INVALID_CURSOR_POS

ERR_INVALID_CURSOR_POS

ERR_INVALID_CURSOR_POS

Error message

Cannot set cursor row without setting its column

What it means

After the NaN checks, cursorTo takes a silent no-op path when the stream is null or BOTH coordinates are non-numbers. It throws ERR_INVALID_CURSOR_POS ('Cannot set cursor row without setting its column') only when y is a number but x is not: you cannot address a row without a column because the emitted ANSI sequence needs both (y+1;x+1 H).

Source

Thrown at ext/node/polyfills/internal/readline/callbacks.mjs:72

function cursorTo(stream, x, y, callback) {
  if (callback !== undefined) {
    validateFunction(callback, "callback");
  }

  if (typeof y === "function") {
    callback = y;
    y = undefined;
  }

  if (NumberIsNaN(x)) throw new ERR_INVALID_ARG_VALUE("x", x);
  if (NumberIsNaN(y)) throw new ERR_INVALID_ARG_VALUE("y", y);

  if (stream == null || (typeof x !== "number" && typeof y !== "number")) {
    if (typeof callback === "function") process.nextTick(callback, null);
    return true;
  }

  if (typeof x !== "number") throw new ERR_INVALID_CURSOR_POS();

  const data = typeof y !== "number" ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
  return stream.write(data, callback);
}

/**
 * moves the cursor relative to its current location
 */

function moveCursor(stream, dx, dy, callback) {
  if (callback !== undefined) {
    validateFunction(callback, "callback");
  }

  if (stream == null || !(dx || dy)) {
    if (typeof callback === "function") process.nextTick(callback, null);
    return true;
  }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Always supply the column when you supply the row: cursorTo(stream, 0, row)
  2. In wrappers, normalize: const X = Number.isFinite(x) ? x : 0 before forwarding
  3. If only a row move is truly needed, emit the relative move with readline.moveCursor(stream, 0, dy) instead

Example fix

// before
readline.cursorTo(stream, undefined, targetRow);

// after
readline.cursorTo(stream, 0, targetRow);
Defensive patterns

Strategy: validation

Validate before calling

function cursorToSafe(stream: NodeJS.WriteStream, x?: number, y?: number) {
  const hasX = Number.isFinite(x);
  const hasY = Number.isFinite(y);
  if (hasX && hasY) readline.cursorTo(stream, x, y);
  else if (hasX) readline.cursorTo(stream, x);
  // never send y without x
}

Try / catch

try {
  readline.cursorTo(stream, x, y);
} catch (err) {
  if (err?.code === 'ERR_INVALID_CURSOR_POS') {
    readline.cursorTo(stream, 0, y);
  } else throw err;
}

Prevention

When it happens

Trigger: readline.cursorTo(process.stdout, undefined, 5); cursorTo(stream, null, 3); x defaulted to undefined by an options-destructuring bug while y was supplied.

Common situations: Wrapper functions like moveTo(stream, opts) that forward opts.x/opts.y when only y was provided; optional-parameter code where the middle argument is skipped: cursorTo(stream, undefined, row).

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/a6eb31262da3b66b. Report an issue: GitHub.