Skip to content

Object.defineProperty(Class, "name", { value }) is silently ignored for classes (zod errors report constructor.name === "Definition") #7190

Description

@proggeramlug

Summary

Object.defineProperty(SomeClass, "name", { value: "X" }) is silently ignored for classes. The same call on a plain function works. Even Object.getOwnPropertyDescriptor(D, "name") reports the original name afterwards, so defineProperty never stored anything — .name keeps resolving through the class registry.

Deterministic, GC-independent, reproduces at d8be5f4a2 in the default configuration.

Minimal repro

class D {}
Object.defineProperty(D, "name", { value: "Renamed" });
console.log("class-name:", D.name);

function f() {}
Object.defineProperty(f, "name", { value: "RenamedFn" });
console.log("fn-name:", f.name);

class Base {}
class Sub extends Base {}
Object.defineProperty(Sub, "name", { value: "SubRenamed" });
console.log("sub-name:", Sub.name);
console.log("ctor-name:", (new (Sub as any)() as any).constructor.name);

const E = class {};
Object.defineProperty(E, "name", { value: "ExprRenamed" });
console.log("expr-name:", (E as any).name);

console.log("desc:", JSON.stringify(Object.getOwnPropertyDescriptor(D, "name")));
line node 26.5.1 perry d8be5f4a2
class-name Renamed D
fn-name RenamedFn RenamedFn
sub-name SubRenamed Sub
ctor-name SubRenamed Sub
expr-name ExprRenamed E
desc {"value":"Renamed","writable":false,"enumerable":false,"configurable":true} {"value":"D",…}

class_object_name_value (crates/perry-runtime/src/object/field_get_set/class_object_props.rs:24) does check own_data_field_by_name before falling back to class_name_for_id, so the miss looks like it is on the store side: defineProperty with key "name" on a class value never installs the own data field. Note Function.prototype.name redefinition works, so the divergence is specific to the class path (INT32 ClassRef vs heap ClassExprFresh).

Why it matters: zod

$constructor (zod/src/v4/core/core.ts) renames both the synthetic base class and the constructor function:

class Definition extends Parent {}
Object.defineProperty(Definition, "name", { value: name });

Object.defineProperty(_, "name", { value: name });

so under perry a caught zod error reports the wrong constructor name:

try { z.string().parse(5); } catch (e: any) { console.log(e.constructor.name); }
// node : ZodError
// perry: Definition

Any user code branching on err.constructor.name (or logging it) sees Definition for every zod error type.

Environment

Node 26.5.1 (.node-version pin), perry @ d8be5f4a2, macOS arm64. Found while investigating #7154.

Refs #7154.

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