Found by a package-compilability probe: redis (@redis/client) now compiles from real source but fails at
runtime, and this is the single blocker.
Cannot read private member from an object whose class did not declare it
@redis/client's classes use JS private (#) fields. Something in Perry's class handling loses the association
between an instance and the class that declared its private fields, so a legitimate this.#x read on an instance
of the declaring class is rejected.
Note this is a correctness bug, not the known perf one. #10501 covers private members being ~1200× slower than
Node; this is separate — the read fails outright.
Why it matters
redis is one of the packages whose hand-written Rust native binding we intend to delete. The probe result is:
compiles ✓, runs ✗, and this error is the only thing standing between the two. Fixing it plausibly makes the
redis binding deletable.
Worth checking first
Several class-identity fixes landed or are in flight this cycle and may be adjacent — the private-field brand
check is exactly the kind of thing that would break if instance→class association is resolved by a shared or
stale id:
If the private-field brand check consults a class id rather than the pinned constructing class, that is the likely
mechanism and #10640's pin_instance_constructing_class is the tool.
Reproduce: npm i redis, a package.json with perry.compilePackages including redis, @redis/client and its
@redis/* siblings, then any client construction. The probe's harness is on perrymaster at
/root/claude-pkgaudit-measure/pkgtest/redis_test.ts.
Found by a package-compilability probe:
redis(@redis/client) now compiles from real source but fails atruntime, and this is the single blocker.
@redis/client's classes use JS private (#) fields. Something in Perry's class handling loses the associationbetween an instance and the class that declared its private fields, so a legitimate
this.#xread on an instanceof the declaring class is rejected.
Note this is a correctness bug, not the known perf one. #10501 covers private members being ~1200× slower than
Node; this is separate — the read fails outright.
Why it matters
redisis one of the packages whose hand-written Rust native binding we intend to delete. The probe result is:compiles ✓, runs ✗, and this error is the only thing standing between the two. Fixing it plausibly makes the
redis binding deletable.
Worth checking first
Several class-identity fixes landed or are in flight this cycle and may be adjacent — the private-field brand
check is exactly the kind of thing that would break if instance→class association is resolved by a shared or
stale id:
instanceofagainst aClassExprFreshparent resolved by sharedclass_idrather than perevaluation, fixed by pinning the constructing class onto each instance.
If the private-field brand check consults a class id rather than the pinned constructing class, that is the likely
mechanism and #10640's
pin_instance_constructing_classis the tool.Reproduce:
npm i redis, apackage.jsonwithperry.compilePackagesincludingredis,@redis/clientand its@redis/*siblings, then any client construction. The probe's harness is on perrymaster at/root/claude-pkgaudit-measure/pkgtest/redis_test.ts.