Skip to content

Derived class that calls super() then returns a Proxy trips "Must call super constructor" — blocks node-fetch after #10759 #10809

Description

@proggeramlug

With #10759 fixed (PR #10807), node-fetch@3.3.2 gets past the Function.prototype.call was called on a value that is not a function failure and hits the next one:

ReferenceError: Must call super constructor in derived class before accessing 'this'
                or returning from derived constructor

raised inside node-fetch's real Headers.js. Pre-existing and separate from #10759 — reported rather than fixed, per that task's scope.

The shape

node-fetch's Headers is a derived class whose constructor calls super(...) and then returns a Proxy wrapping this:

export default class Headers extends URLSearchParams {
  constructor(init) {
    // ...normalise init into `result`...
    super(result);
    return new Proxy(this, { get(target, p, receiver) { /* ... */ } });
  }
}

That is legal JavaScript and Node executes it without complaint. Perry raises the derived-constructor guard anyway.

Worth noting the guard is doing its job in general — this is not a claim that the check is wrong, but that something in this shape (a super() call followed by a constructor-return override, with a Proxy as the returned value) is not being recognised as having satisfied it.

Why it is worth attention beyond node-fetch

The constructor-return-override is not exotic. Returning a Proxy from a constructor is the standard way to give a class a dynamic property surface, and doing it from a derived class — after super() — is exactly what a subclass of a builtin must do. Anything wrapping a builtin this way is a candidate.

Reproduction

mkdir nf-probe && cd nf-probe
npm install node-fetch@3.3.2
# package.json: { "perry": { "compilePackages": ["node-fetch"] } }
# fixture.ts: import fetch from "node-fetch"; then a GET against a local node:http server
perry compile fixture.ts -o fixture && ./fixture

A package-independent reduction is the obvious first step and was not attempted: a derived class extending a builtin, calling super(), then returning new Proxy(this, {...}). If that reproduces, node-fetch is incidental.

Status

This is the second distinct defect in node-fetch's path, after #10759. Real-source node-fetch remains blocked, and its binding should not be removed until this is resolved. #10759's fix is correct and complete for what it claims — its gap test covers the same derived-class-plus-Proxy shape and passes byte-for-byte against Node — but the package needs both.

Activity

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

    package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindings

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions