denoland/deno · error · ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

ERR_INVALID_ARG_TYPE("stream", "Writable", stream)

What it means

The Readline helper class in node:readline/promises (used for cursor control on a single output stream) requires its constructor argument to be a Writable stream. The polyfill checks isWritable(stream) from internal/streams/utils and throws ERR_INVALID_ARG_TYPE('stream', 'Writable', stream) for anything else — strings, numbers, readables like process.stdin or fs.createReadStream().

Source

Thrown at ext/node/polyfills/internal/readline/promises.mjs:42

const { ERR_INVALID_ARG_TYPE } = core.loadExtScript(
  "ext:deno_node/internal/errors.ts",
);

const {
  kClearToLineBeginning,
  kClearToLineEnd,
  kClearLine,
  kClearScreenDown,
} = CSI;

class Readline {
  #autoCommit = false;
  #stream;
  #todo = [];

  constructor(stream, options = undefined) {
    if (!isWritable(stream)) {
      throw new ERR_INVALID_ARG_TYPE("stream", "Writable", stream);
    }
    this.#stream = stream;
    if (options?.autoCommit != null) {
      validateBoolean(options.autoCommit, "options.autoCommit");
      this.#autoCommit = options.autoCommit;
    }
  }

  /**
   * Moves the cursor to the x and y coordinate on the given stream.
   * @param {integer} x
   * @param {integer} [y]
   * @returns {Readline} this
   */
  cursorTo(x, y = undefined) {
    validateInteger(x, "x");
    if (y != null) validateInteger(y, "y");

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass a Writable: process.stdout, process.stderr, or fs.createWriteStream(path)
  2. If you meant a full prompt interface, use createInterface({ input, output }) instead of new Readline(stream)
  3. Check the argument: typeof stream?.write === 'function' before constructing

Example fix

// before
const rl = new Readline('log.txt');

// after
const rl = new Readline(fs.createWriteStream('log.txt'));
Defensive patterns

Strategy: type-guard

Validate before calling

import { Readline } from 'node:readline/promises';

function makeReadline(stream: unknown) {
  if (stream && typeof (stream as NodeJS.WritableStream).write === 'function') {
    return new Readline(stream as NodeJS.WritableStream);
  }
  throw new TypeError('stream must be a Writable (e.g. process.stdout)');
}

Type guard

const isNodeWritable = (s: unknown): s is NodeJS.WritableStream =>
  !!s && typeof (s as NodeJS.WritableStream)?.write === 'function';

Try / catch

try {
  rl = new Readline(stream);
} catch (err) {
  if (err?.code === 'ERR_INVALID_ARG_TYPE' && /Writable/.test(err.message)) {
    rl = new Readline(process.stdout);
  } else throw err;
}

Prevention

When it happens

Trigger: new Readline(process.stdin); new Readline('out.txt'); new Readline(fs.createReadStream(p)); passing the interface itself or null where a Writable is expected; forgetting the argument so stream is undefined.

Common situations: Confusing input/output when wiring terminal helpers (stream must be the output side, e.g. process.stdout); passing a file path string instead of a write stream; using the Readline class where createInterface({ input, output }) was intended.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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