zod
zod copied to clipboard
Error when using `coerce` function V4
Hi,
Here is my schema before migrate to V4
const schema = z.string().date({ message: 'Invalid ISO 8601 date-time format. Expected formats: YYYY-MM-DDTHH:MM:SS.sssZ' }) .pipe(z.coerce.date())
after migrate to V4
const schema = z.iso.datetime({ error: 'Invalid ISO 8601 date-time format. Expected formats: YYYY-MM-DDTHH:MM:SS.sssZ', }) .pipe(z.coerce.date())
schema.safeParse('invalid data')
Then it will return errors
error: ZodError: [ { "origin": "string", "code": "invalid_format", "format": "datetime", "pattern": "/^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$/", "path": [], "message": "Invalid ISO 8601 date-time format. Expected formats: YYYY-MM-DDTHH:MM:SS.sssZ" }, { "expected": "date", "code": "invalid_type", "received": "Invalid Date", "path": [], "message": "Invalid input: expected date, received Date" } ]
Before migrating to v4, it only returned the first issue instead of both. By using .transform((value) => new Date(value) it still work as normal. Is this expected?
Hi @nguyendhuy1997! I'm Dosu and I’m helping the zod team.
This is expected in Zod v4. The .pipe() method now collects errors from both the input and output schemas, so when you use something like z.iso.datetime().pipe(z.coerce.date()), you'll get errors for both the format (from the ISO datetime check) and the type (from the date coercion) if the input fails both stages. This is an intentional design change to provide more comprehensive error reporting and make debugging easier [docs].
If you want to replicate the old behavior (only the first error), you can use .transform() or .preprocess() instead, which will typically stop at the first failure. For example:
const schema = z.iso.datetime().transform((value) => new Date(value));
Or, using z.preprocess:
const schema = z.preprocess(
(val) => typeof val === "string" ? new Date(val) : val,
z.date()
);
For more details on the new error handling and .pipe() behavior, see the v4 changelog and API docs.
Let me know if this answers your question or if you need more help! If you're satisfied, feel free to close the issue.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
In Zod 4, only invalid_type issues are considered "non-continuable". For other issue types (including the invalid_format issue produced by z.iso.datetime()) validation will continue (including across pipes) by default. You can change this with the abort flag:
const schema = z.iso
.datetime({ error: "Invalid ISO 8601 date-time format. Expected formats: YYYY-MM-DDTHH:MM:SS.sssZ", abort: true })
.pipe(z.coerce.date());
console.log(schema.safeParse("invalid data")); // only one issue