Skip to content

zod v4: .string().min() (checks) crashes — ch._zod.onattach undefined under compilePackages #4698

@proggeramlug

Description

@proggeramlug

Repro

package.json: { "perry": { "compilePackages": ["zod"], "allow": { "compilePackages": ["zod"] } } }

import { z } from "zod";
console.log(z.string().min(2).parse("hello"));

Perry:

TypeError: Cannot read properties of undefined (reading 'onattach')
    at <anonymous>

Node (--experimental-strip-types): hello

Any schema with a check (.min, .max, .length, .regex, .email, numeric .gt/.lt, …) hits this — z.string()/z.object().parse() without checks works.

Analysis

In zod's $ZodType initializer (node_modules/zod/src/v4/core/schemas.ts):

const checks = [...(inst._zod.def.checks ?? [])];
for (const ch of checks) {
  for (const fn of ch._zod.onattach) { fn(inst); }   // ch._zod is undefined
}

A check instance in def.checks comes back without _zod. The check is built by new $ZodCheckMinLength({...}) (a $constructor that installs _zod via Object.defineProperty(inst, "_zod", { value, enumerable:false })), threaded through inst.check()util.mergeDefs(def, { checks:[...] }) (which round-trips via Object.getOwnPropertyDescriptors + Object.defineProperties) → core.clone().

Not reproducible standalone: a faithful standalone model of the entire $constructor + $ZodCheck.init + onattach.push + mergeDefs (getOwnPropertyDescriptors/defineProperties round-trip) + [...def.checks] spread chain runs correctly in Perry (byte-matches Node). So the _zod loss is specific to the cross-module perry.compilePackages compilation of real zod — a check instance constructed in core/checks.ts and read back through core/schemas.ts / core/util.ts loses its non-enumerable _zod property somewhere across the module boundary.

Context

Follow-up to discussion #3438. The core object-parse crash (reading '_zod' of undefined) is fixed by #4697 (Object.defineProperty attribute retention); with that fix, z.object() / nested / array / boolean / optional parsing works. This checks-path bug and the safeParse error-path bug (separate issue) remain. Refs #793.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparityNode.js compatibility / parity gaps

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions