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 the stream subsystem.

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions