Skip to content

stream/iter: merge() treats valid object-like sources as options #63355

@trivikr

Description

@trivikr

Version

26.1.0

Platform

macOS 26.5.0

Subsystem

stream

What steps will reproduce the bug?

import assert from 'node:assert/strict';
import { from, merge, text, toStreamable } from 'node:stream/iter';

const arrayBuffer = new TextEncoder().encode('abc').buffer;
const protocolObject = {
  [toStreamable]() {
    return 'abc';
  },
};

assert.deepStrictEqual({
  directArrayBuffer: await text(from(arrayBuffer)),
  mergedArrayBuffer: await text(merge(arrayBuffer)),
  directProtocol: await text(from(protocolObject)),
  mergedProtocol: await text(merge(protocolObject)),
}, {
  directArrayBuffer: 'abc',
  mergedArrayBuffer: 'abc',
  directProtocol: 'abc',
  mergedProtocol: 'abc',
});

Run with

node --experimental-stream-iter --no-warnings repro.mjs

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

Always

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

No assertion error.

merge(source) should accept the same valid object-like sources as from(source), including ArrayBuffer and Stream.toStreamable objects.

What do you see instead?

Assertion error

node:internal/modules/run_main:107
    triggerUncaughtException(
    ^

AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected

  {
    directArrayBuffer: 'abc',
    directProtocol: 'abc',
+   mergedArrayBuffer: '',
+   mergedProtocol: ''
-   mergedArrayBuffer: 'abc',
-   mergedProtocol: 'abc'
  }

    at file:///Users/trivikram/workspace/test-repro/repro.js:11:8
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: {
    directArrayBuffer: 'abc',
    mergedArrayBuffer: '',
    directProtocol: 'abc',
    mergedProtocol: ''
  },
  expected: {
    directArrayBuffer: 'abc',
    mergedArrayBuffer: 'abc',
    directProtocol: 'abc',
    mergedProtocol: 'abc'
  },
  operator: 'deepStrictEqual',
  diff: 'simple'
}

merge() classifies the final non-iterable object as options, drops it from sources, and returns '' for those cases.

Additional information

No response

Metadata

Metadata

Assignees

Labels

streamIssues and PRs related to the stream subsystem.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions