denoland/deno · error · ERR_ILLEGAL_CONSTRUCTOR

ERR_ILLEGAL_CONSTRUCTOR

ERR_ILLEGAL_CONSTRUCTOR

Error message

Illegal constructor

What it means

The stream compat layer exposes stream-returning operators (pipeline/compose-style helpers) as methods installed on `Stream.Readable.prototype`. Each generated wrapper checks `new.target` and throws ERR_ILLEGAL_CONSTRUCTOR when invoked with `new`, because these are plain factory functions, not classes — their whole job is to call the operator and wrap its result in `Readable.from` or similar.

Source

Thrown at ext/node/polyfills/stream.ts:93

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

Stream.isDestroyed = utils.isDestroyed;
Stream.isDisturbed = utils.isDisturbed;
Stream.isErrored = utils.isErrored;
Stream.isReadable = utils.isReadable;
Stream.isWritable = utils.isWritable;

Stream.Readable = Readable;
const streamKeys = ObjectKeys(streamReturningOperators);
for (let i = 0; i < streamKeys.length; i++) {
  const key = streamKeys[i];
  const op = streamReturningOperators[key];
  function fn(...args) {
    if (new.target) {
      throw new ERR_ILLEGAL_CONSTRUCTOR();
    }
    return Stream.Readable.from(ReflectApply(op, this, args));
  }
  ObjectDefineProperty(fn, "name", { __proto__: null, value: op.name });
  ObjectDefineProperty(fn, "length", { __proto__: null, value: op.length });
  ObjectDefineProperty(Stream.Readable.prototype, key, {
    __proto__: null,
    value: fn,
    enumerable: false,
    configurable: true,
    writable: true,
  });
}
const promiseKeys = ObjectKeys(promiseReturningOperators);
for (let i = 0; i < promiseKeys.length; i++) {
  const key = promiseKeys[i];
  const op = promiseReturningOperators[key];
  function fn(...args) {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Call the operator without `new`: `const merged = a.compose(b);`
  2. Wrap operators in functions, not classes, when building utilities
  3. Fix typings: these are `(...args: any[]) => Readable` signatures with no construct signature

Example fix

// before
const merged = new a.compose(b);
// ERR_ILLEGAL_CONSTRUCTOR

// after
const merged = a.compose(b);
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: `new readable.compose(other)` or any `new`-invocation of an operator method from the streamReturningOperators set installed on Readable.prototype.

Common situations: Code generators or bundlers that wrap functions in classes; developers assuming every exported stream helper is a class like `new Stream.Readable()`; TypeScript typings that mistakenly declare these methods constructable.

Related errors


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