Skip to content

runtime: builtins must throw spec-mandated TypeError/RangeError on invalid this/args #3662

Closed

Description

@proggeramlug

Summary

Built-in functions and methods do not throw the spec-mandated TypeError /
RangeError on invalid arguments or invalid this. A parity sweep shows 282
failures
with the signature "Expected a … to be thrown but no exception was
thrown at all" (test262) / "Missing expected exception" (node-core) — the single
largest behavioral cluster in the report.

This is the runtime-validation side of Perry's "no runtime type validation"
design: where the spec requires an operation to reject bad input, Perry silently
proceeds.

Evidence (from scripts/parity_gap_report.py, 2026-05-31)

282 failures. Top categories: Set (28), WeakSet (28), Function (24), WeakMap
(23), fs (20), Map (13), TypedArray (11), buffer (8), process (8), zlib (8),
http (6), ArrayBuffer (5).

The cleanest sub-pattern is this-not-object / not-callable brand checks —
e.g. calling a Set/Map/WeakSet/WeakMap prototype method with a non-object this
must throw, and Function.prototype.apply/bind/Symbol.hasInstance must reject a
non-callable this:

  • built-ins/Set/prototype/{add,delete,forEach,has,values}/this-not-object-throw.js
  • built-ins/WeakSet/prototype/{add,delete,has}/this-not-object-throw.js
  • built-ins/WeakMap/prototype/{...}/this-not-object-throw.js
  • built-ins/Function/prototype/apply/this-not-callable-realm.js
  • built-ins/Function/prototype/Symbol.hasInstance/{this-val-not-callable,value-non-obj}.js

On the node-core side the same gap surfaces as missing ERR_INVALID_ARG_TYPE /
ERR_OUT_OF_RANGE throws across fs / buffer / process / zlib.

Repro

const s = new Set();
Set.prototype.add.call({}, 1);   // should throw TypeError (this is not a Set); Perry: no throw

Function.prototype.apply.call(undefined, null, []);  // should throw TypeError; Perry: no throw

Why it's high-leverage

One semantic — "perform the spec's brand/type check and throw before doing the
work" — applied across the collection prototypes and Function.prototype clears
the largest single block of failures (~100+ from Set/Map/Weak*/Function alone),
and the same pattern extends to the node-core arg-validation cases.

Suggested scope

Add the this/argument brand checks at the top of the affected builtin methods
(Set/Map/WeakSet/WeakMap prototype methods, Function.prototype.apply/bind/
hasInstance) and the constructor/method arg-range checks for the node-core APIs,
each throwing the spec-correct error type.


Filed from the parity-gap radar. Cluster: 282 "no exception was thrown" /
"Missing expected exception" failures across ~25 categories.

Activity

  1. proggeramlug commented on Jun 2, 2026

    @proggeramlug
    ContributorAuthor

    Status / decomposition (2026-06-02)

    This umbrella (~282 "no exception thrown" failures) has been largely cleared by
    general work + targeted PRs. A re-sweep against node --experimental-strip-types
    shows most categories now behave correctly (Set/Map/Weak*, Function apply/call/bind,
    fs/zlib/process, all String.prototype this-coercibility, ArrayBuffer/TypedArray
    prototype this checks, Number toFixed/toString/etc.).

    Merged sub-clusters

    Open PRs

    Remaining tail — filed as granular issues (per the workable-backlog preference):

    Suggest closing this umbrella once #4093 + #4098 land, tracking the rest via the
    granular issues above.

  2. proggeramlug commented on Jun 2, 2026

    @proggeramlug
    ContributorAuthor

    Update: the #4099 crash (highest-value remaining item) now has a fix in PR #4111 — installing the collection size accessor before the data methods (root-caused to an accessor-install desync corrupting Map.prototype.set). The pre-existing test_gap_3662_collection_brand_check.ts (which crashed on main) now passes. Remaining: #4100 (primitive-wrapper brand checks), #4101, #4102, #4103.

  3. proggeramlug commented on Jun 2, 2026

    @proggeramlug
    ContributorAuthor

    Final disposition (this work cycle)

    The substantive, tractable items are fixed and the remainder is decomposed into granular, investigation-backed issues.

    Shipped this cycle (CI-green):

    Remaining — tracked, each needs a deeper/architectural change (not the collection recipe):

    Recommend closing this umbrella once #4093/#4098/#4111 merge, and letting #4100–#4103 proceed as independent issues.

  4. proggeramlug commented on Jun 2, 2026

    @proggeramlug
    ContributorAuthor

    Resolved — full cluster verified byte-identical to Node

    All decomposed sub-issues are fixed and merged, and the whole cluster was re-verified end-to-end against node --experimental-strip-types on a clean main build (HEAD includes #4124):

    Area Fixed by
    Collection (Set/Map/WeakMap/WeakSet) brand checks #3739
    Function.prototype.{apply,call,bind} not-callable this #4073
    node-core arg validation (fs/zlib/process) #4082
    Typed-array constructor length RangeError #4093
    Function.prototype[Symbol.hasInstance] #4098
    Map/WeakMap.set reflective crash → TypeError (#4099) #4111 + #4113
    dynamic instanceof Array/Object/Date (#4102) #4107
    typed-array view offset/length + alignment (#4103) #4107
    Function.prototype.toString source + brand check (#4101) #4108
    Number/Boolean/Symbol/BigInt prototype brand checks (#4100) #4112 + #4124 (typed .call)

    Spot-checked all of: collection/Function/String/Number/Boolean/Symbol/BigInt prototype this brand checks (computed and statically-typed .call), typed-array constructor + view validation, hasInstance, dynamic instanceof, and Function.prototype.toString — every case matches Node.

    Closing as completed.

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