Weird error message when z.coerce.date() fails to coerce
Summary
When using z.coerce.date() with a value that cannot be coerced into a valid Date, the error message is misleading:
z.coerce.date().parse('www');
// => ZodError: Invalid input: expected date, received Date
This reads as if a Date was provided, when in fact a string was provided and the coercion produced an invalid Date. It would be helpful if the error communicated that coercion failed and/or showed the original input type/value.
Repro
import { z } from 'zod';
const schema = z.coerce.date();
schema.parse('www'); // Invalid input: expected date, received Date
schema.parse('not-a-date'); // same
schema.parse('2025-13-99'); // same (invalid calendar date)
(Using Zod v4 — reproducible in a fresh project.)
Actual behavior
- Error message:
Invalid input: expected date, received Date - This suggests the input was a
Date, which is incorrect. The input was a string and the coercion producednew Date("www")→Invalid Date.
Expected behavior
A clearer message, for example (any of these would be great):
Invalid date: could not coerce value "www" into a valid DateInvalid input: expected a date, received string "www" (coercion failed)Invalid input: expected valid Date after coercion, got Invalid Date (from "www")
Key points:
- Indicate original input type/value (string
"www"). - Indicate that coercion happened and failed because the result is an Invalid Date.
Why this matters
- The current message can send users on a wild goose chase, thinking they’re passing a
Dateincorrectly. - Clearer messaging speeds up debugging, especially in schemas with nested objects where the path matters.
Possible directions (implementation ideas)
-
In the
coerce.date()pipeline, after coercion (new Date(value)), detectNumber.isNaN(date.getTime()):-
If
Invalid Date, raise a custom issue code (e.g.,"invalid_date") that includes:- the original input type and a safe preview of the value,
- a hint that coercion failed.
-
-
Alternatively, adjust the error constructor for
ZodDateto include a special branch when the input is already aDatebut invalid vs. when the input was coerced from a non-Date type and resulted inInvalid Date. -
(Nice-to-have) Add a short value preview with truncation and JSON-stringify to avoid giant messages.
Environment
- Zod: v4.x
- Node: v18+/v20 (reproducible)
- TS: 5.x
Minimal code sandbox
import { z } from 'zod';
z.coerce.date().parse('www');
Thanks for the awesome library! 🙌
Hi @AlonMiz! I'm Dosu and I’m helping the zod team.
You're right—when z.coerce.date() fails to coerce a string into a valid Date, the default error message can be misleading. This happens because Zod checks if the result is a Date instance, but doesn't distinguish between a valid and an invalid Date object, so the error message ends up saying "expected date, received Date" even if the original input was a string that failed coercion.
This behavior is recognized in the community and has been discussed in several issues and discussions. The recommended workaround is to use a custom errorMap on your schema to provide a clearer message for the "invalid_date" error code. For example:
const schema = z.coerce.date({
errorMap: (issue, { defaultError }) =>
issue.code === "invalid_date"
? { message: `Could not coerce value into a valid Date` }
: { message: defaultError },
});
schema.parse('www'); // Throws: Could not coerce value into a valid Date
If you want to include the original input in the error, you can enable the reportInput flag during parsing and use issue.input in your error map:
schema.parse('www', { reportInput: true });
// In errorMap: issue.input will be 'www'
This approach is currently the best way to get more informative error messages for date coercion failures in Zod v4. If this answers your question, please close the issue!
References: custom errorMap workaround, related issue, error customization docs.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other