Skip to content

[@conform-to/zod] getConstraints/getZodConstraint lose minLength/maxLength/pattern/min/max/accept on zod >= 4.6 (checks no longer written to _zod.bag) #1340

Description

@devin-ai-integration

Describe the bug and the expected behavior

Since zod 4.6.0, getConstraints() (@conform-to/zod/v4/future) and getZodConstraint() (@conform-to/zod/v4) silently drop every constraint derived from checks: minLength, maxLength, pattern (from .regex()), min, max and accept. Only required, multiple and the enum pattern survive.

Root cause: v4/constraint.ts reads the check metadata from the schema's _zod.bag (bag.minimum, bag.maximum, bag.patterns, bag.mime). Zod 4.6 stopped writing that metadata onto the bag at construction time – checks are now folded lazily (aggregateChecks() in core/json-schema-processors), and the Zod Classic accessors .minLength / .maxLength / .minValue / .maxValue / .format became getters that are computed on first read (see "members materialize on first read" in the Zod 4.6 release notes, zod PR #6554). So on 4.6 schema._zod.bag is {} for a plain z.string().min(2) even though schema.minLength === 2.

Expected: the same constraints as on zod ≤ 4.5. Possible fix: read the Classic getters (schema.minLength, schema.maxLength, schema.minValue, schema.maxValue, …) where available, or fold def.checks ($ZodCheckMinLength, $ZodCheckMaxLength, $ZodCheckGreaterThan, $ZodCheckLessThan, $ZodCheckRegex, $ZodCheckMimeType, …) directly instead of relying on the bag, which zod treats as internal.

Affects @conform-to/zod 1.20.x and 1.21.1 (peer range ^3.21.0 || ^4.0.0 includes 4.6).

Conform version

@conform-to/zod 1.21.1 (also 1.20.1), zod 4.6.0 – 4.6.4 (works on 4.5.4)

Steps to Reproduce the Bug or Issue

import { getConstraints } from "@conform-to/zod/v4/future";
import { z } from "zod";

const schema = z.object({
  name: z.string().min(2).max(50).regex(/^[a-z]+$/),
  age: z.number().min(18).max(99),
  avatar: z.file().mime(["image/png"]),
});

console.log(JSON.stringify(getConstraints(schema)));
console.log(JSON.stringify(schema.shape.name._zod.bag), schema.shape.name.minLength);

zod 4.5.4:

{"name":{"required":true,"minLength":2,"maxLength":50,"pattern":"^(?=.*(?:^[a-z]+$)).*$"},"age":{"required":true,"min":18,"max":99},"avatar":{"required":true,"accept":"image/png"}}
{"minimum":2,"maximum":50,"format":"regex","patterns":{}} 2

zod 4.6.4:

{"name":{"required":true},"age":{"required":true},"avatar":{"required":true}}
{} 2

What browsers are you seeing the problem on?

No response (Node 24, runtime-independent)

Screenshots or Videos

No response

Additional context

Parsing/coercion (coerceFormValue, formatResult, parseWithZod) is unaffected; only the constraint extraction for the HTML attributes regresses.

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions