Skip to content

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

Closed

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

  1. added
    package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindings
    on Sep 20, 2026
  2. proggeramlug commented on Sep 21, 2026

    @proggeramlug
    ContributorAuthor

    Re-tested this against current main (47ade47327) with the real node-fetch@3.3.2 source graph (22 compiled modules: node-fetch, data-uri-to-buffer, fetch-blob, formdata-polyfill, node-domexception, and web-streams-polyfill).

    The reported derived-constructor failure is no longer reproducible: Headers gets through super(...) and its Proxy return without the Must call super constructor error. The existing test_gap_10759_urlsearchparams_prototype_method_value.ts reduction also passes.

    The full local-HTTP fixture now reaches a later, separate HTTP integration failure:

    RESULT: ERROR Error: Invalid response handle
        at new __AnonShape_105fb05143d2f2d2 (<anonymous>)
    

    This result establishes only that the original symptom does not reproduce on current main; the cause of the difference from the earlier run is unknown. The current node-fetch blocker is tracked separately in #10887.

  3. proggeramlug commented on Sep 21, 2026

    @proggeramlug
    ContributorAuthor

    Closing this report because its specific derived-constructor failure no longer reproduces on current main; the reason for the difference from the original run is unknown. The newly observed node-fetch failure is tracked independently in #10887.

  4. proggeramlug commented on Sep 21, 2026

    @proggeramlug
    ContributorAuthor

    Reopening after a fully coherent rebuild of current main (f88acdaa1b) reproduced the original Must call super constructor failure with the clean public-entry node-fetch@3.3.2 fixture. The earlier non-reproduction used a compiler/runtime build containing the pending #10886 changes, so it was not a valid pristine-main result. #10887 remains the next observed blocker on top of that pending fix.

  5. proggeramlug commented on Sep 22, 2026

    @proggeramlug
    ContributorAuthor

    Confirmed reproducing cleanly on current main while re-validating node-fetch after its original blocker (#10759) landed. Full fixture: node-fetch@3.3.2, perry.compilePackages: ["node-fetch"], a self-hosted http.createServer + fetch() round trip (GET /json, POST /echo). Compiles and links (needs the full auto-optimize path — see #10671 for a separate, unrelated link-coherence gap this package also hits under PERRY_NO_AUTO_OPTIMIZE=1), then:

    node-fetch version: 3.3.2
    ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
        at <anonymous>
    

    Node runs the identical fixture cleanly (GET json: {"hello":"world"}, POST echo: {"a":1}). This is the last blocker standing between node-fetch and a full real-source pass — once this lands, re-validating with the same fixture should confirm the package end-to-end.

  6. proggeramlug commented on Oct 4, 2026

    @proggeramlug
    ContributorAuthor

    Re-checked on main b73093e: the reported "Must call super constructor" no longer reproduces. node-fetch's real Headers.js runs, and so do the URLSearchParams-subclass, builtin-parent, derived-of-derived and async-constructor shapes. A related crash in the same code (a derived constructor returning new Proxy(this) segfaulted once enough Proxies existed) is fixed by #11933. The node-fetch GET fixture now stops at a separate empty Error, tracked as #10887. Closing this as fixed on main.

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