Skip to content

stream/iter: Writer methods do not consistently validate options.signal #64384

Description

@trivikr

Version

main

Platform

macOS 26.5.2

Subsystem

stream

What steps will reproduce the bug?

import { Writable } from 'node:stream';
import {
  broadcast,
  fromWritable,
  push,
} from 'node:stream/iter';

const badOptions = { signal: 'not an AbortSignal' };

const classicWritable = new Writable({
  write(chunk, encoding, callback) {
    callback();
  },
});

const cases = [
  ['push().writer.write()', () => push().writer.write('x', badOptions)],
  ['push().writer.writev()', () => push().writer.writev(['x'], badOptions)],
  ['push().writer.end()', () => push().writer.end(badOptions)],

  ['broadcast().writer.write()', () => broadcast().writer.write('x', badOptions)],
  ['broadcast().writer.writev()', () => broadcast().writer.writev(['x'], badOptions)],
  ['broadcast().writer.end()', () => broadcast().writer.end(badOptions)],

  ['fromWritable().write()', () => fromWritable(classicWritable).write('x', badOptions)],
  ['fromWritable().writev()', () => fromWritable(classicWritable).writev(['x'], badOptions)],
  ['fromWritable().end()', () => fromWritable(classicWritable).end(badOptions)],
];

for (const [name, run] of cases) {
  try {
    const result = run();
    if (result?.then) {
      await result;
    }
    console.log(`${name}: resolved`);
  } catch (err) {
    console.log(`${name}: ${err.code ?? err.name}: ${err.message}`);
  }
}

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

push().writer.write(): ERR_INVALID_ARG_TYPE: ...
push().writer.writev(): ERR_INVALID_ARG_TYPE: ...
push().writer.end(): ERR_INVALID_ARG_TYPE: ...
broadcast().writer.write(): ERR_INVALID_ARG_TYPE: ...
broadcast().writer.writev(): ERR_INVALID_ARG_TYPE: ...
broadcast().writer.end(): ERR_INVALID_ARG_TYPE: ...
fromWritable().write(): ERR_INVALID_ARG_TYPE: ...
fromWritable().writev(): ERR_INVALID_ARG_TYPE: ...
fromWritable().end(): ERR_INVALID_ARG_TYPE: ...

A proper invalid-argument TypeError for options.signal, ideally Node’s usual ERR_INVALID_ARG_TYPE, because the spec defines WriteOptions.signal as an AbortSignal.

What do you see instead?

push().writer.write(): TypeError: signal?.throwIfAborted is not a function
push().writer.writev(): TypeError: signal?.throwIfAborted is not a function
push().writer.end(): resolved
broadcast().writer.write(): TypeError: signal?.throwIfAborted is not a function
broadcast().writer.writev(): TypeError: signal?.throwIfAborted is not a function
broadcast().writer.end(): resolved
fromWritable().write(): resolved
fromWritable().writev(): resolved
fromWritable().end(): resolved

Additional information

No response

Metadata

Metadata

Assignees

Labels

streamIssues and PRs related to Node.js streams.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions