Skip to content

runtime: a subclass method overriding a native base method (EventEmitter.emit) is silently bypassed — override never runs #6316

Closed

Description

@proggeramlug

Summary

A user method that overrides a native base-class method is silently bypassed: the call dispatches straight to the native implementation and the override never runs. super.<method>() from inside such an override also doesn't reach the base.

Confirmed on a clean origin/main build (0960415ad).

Repro

import { EventEmitter } from "node:events";

class Bus extends EventEmitter {
  emit(ev: string, ...args: any[]): boolean {
    console.log("override ran:", ev);
    return super.emit(ev, ...args);
  }
}

const b = new Bus();
b.on("ping", (x: number) => console.log("listener got:", x));
console.log("emit returned:", b.emit("ping", 42));
output
node 26 override ran: ping / listener got: 42 / emit returned: true
perry main listener got: 42 / emit returned: true

The override ran: line is missing — b.emit(...) went directly to the native EventEmitter.emit, skipping the user's method entirely. No error, no warning.

Why it matters

Subclassing EventEmitter and overriding emit/on to add logging, filtering, or instrumentation is an extremely common Node pattern. Today it silently does nothing, which is a wrong answer rather than a crash — the worst failure mode.

Scope

Surfaced while fixing #6301 (class X extends EventTarget inheriting nothing). That issue's fix routes EventTarget methods through the class chain and places them last on the lookup path so a subclass override wins. This issue is the mirror problem for native bases generally: the override is not consulted at all.

Two things to establish:

  1. Which native base classes are affected (EventEmitter confirmed; check EventTarget, Error, Array, Promise, stream classes).
  2. Whether the dispatch bypass and the super.<method>() failure are one root cause or two.

Note super.<method>() into a native base was independently observed as broken during #6301 and scoped out of that PR as orthogonal — this is its tracking issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed defect or regression

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions