Skip to content

Exceptions thrown by start() are not rethrown from the TransformStream / ReadableStream / WritableStream constructors #7693

Open

Description

@mikepage

Which Cloudflare product(s) does this pertain to?

Workers Runtime (workerd).

What versions & operating system are you using?

workerd 1.20261011.1 and 1.20260730.1, compatibility date 2026-10-11 and
2026-07-30, no compatibility flags. macOS 26.7.1 (arm64). Same result at
compatibility date 2022-11-30, with streams_enable_constructors +
transformstream_enable_standard_constructor at 2021-11-03, and with
pedantic_wpt.

Please provide a minimal reproduction

const start = () => {
  throw new RangeError("boom");
};

function construct(make) {
  try {
    make();
    return "constructor returned";
  } catch (e) {
    return `constructor threw ${e.name}: ${e.message}`;
  }
}

export default {
  fetch() {
    return Response.json({
      TransformStream: construct(() => new TransformStream({ start })),
      ReadableStream: construct(() => new ReadableStream({ start })),
      WritableStream: construct(() => new WritableStream({ start })),
    });
  },
};

Describe the bug

When start() throws synchronously, the constructor returns normally and the
stream is errored with the exception instead (for the TransformStream, a
later readable read rejects with it). Code that validates its arguments in start() therefore never throws
from new.

The start algorithms run through maybeRunAlgorithm() in
src/workerd/api/streams/standard.c++,
which turns a synchronous throw into a rejected promise
(ReadableImpl::start L1070, the writable start L1702, the transformer start
L4710). That is right for pull(), write() and the others, but not for
start().

Hit by Deno std's ByteSliceStream, which throws a RangeError from
start() for a negative start index. Its test (ByteSliceStream,
assertThrows(() => createStream(-1, Infinity))) fails with "Expected
function to throw."

Expected

All three constructors throw RangeError: boom, as in Chromium 152 and Node
24.18.

Actual

{"TransformStream":"constructor returned","ReadableStream":"constructor returned","WritableStream":"constructor returned"}

🤖 Generated with Claude Code

Activity

  1. jasnell commented on Oct 11, 2026

    @jasnell
    Collaborator

    Yep, known divergence. Will need a compat flag in the legacy impl to fix. Will have to test whether the new TS impl covers this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions