zod icon indicating copy to clipboard operation
zod copied to clipboard

`z.literal` message not customizable

Open craig-jennings opened this issue 1 year ago • 5 comments

When I try to customize the message of a z.literal, I get the following output:

try {
  z.literal('correct', { message: 'must match' }).parse('incorrect');
} catch (err) {
  console.log('err: ', err);
}

//  err:  ZodError: [
//    {
//      "received": "incorrect",
//      "code": "invalid_literal",
//      "expected": "correct",
//      "path": [],
//      "message": "Invalid literal value, expected \"correct\""
//    }
//  ]

when I would expect to get

//  err:  ZodError: [
//    {
//      "received": "incorrect",
//      "code": "invalid_literal",
//      "expected": "correct",
//      "path": [],
//      "message": "must match"
//    }
//  ]

craig-jennings avatar May 03 '24 16:05 craig-jennings

This landed in a recent version of Zod, you'll need to upgrade to v3.23.0+

colinhacks avatar May 03 '24 20:05 colinhacks

I'm getting that behavior on 3.25.6. In using https://zod-playground.vercel.app/, if I have z.literal('test', { message: 'wrong' }) and give undefined, the message shows as expected (see screenshot below). However, if I have the wrong value the message goes back to the default one (second screenshot). image image

Note this doesn't happen with other Zod types: image

craig-jennings avatar May 03 '24 22:05 craig-jennings

@colinhacks I think this is still an issue in v3.25.6 (see above)

craig-jennings avatar May 06 '24 13:05 craig-jennings

also v3.23.8

LiMao00 avatar Jun 25 '24 08:06 LiMao00

This issue is still happening. Please re-open.

huy-nguyen avatar Oct 17 '24 18:10 huy-nguyen

up

mathcovax avatar May 27 '25 17:05 mathcovax

Hi @craig-jennings! I'm Dosu and I’m helping the zod team.

You're correct—custom error messages for z.literal aren't applied for incorrect values in Zod v3.25.6. This happens because the implementation doesn't attach the message param to invalid_literal issues, so the default error message is always used for literal mismatches, even though other types like z.string do respect custom messages for their errors. You can see this in the code for ZodLiteral and the error map logic here.

As a workaround, you can globally override error messages using a custom error map with z.setErrorMap. For example:

import { z } from "zod";

z.setErrorMap((issue, ctx) => {
  if (issue.code === z.ZodIssueCode.invalid_literal) {
    return { message: "must match" };
  }
  return { message: ctx.defaultError };
});

This will apply your custom message to all literal mismatches. More details are in the docs.

If you want more granular control or per-schema messages, Zod v4 introduces a new error customization API that lets you use a function to generate error messages based on the issue, which resolves this inconsistency see discussion. If possible, consider upgrading to v4 for more flexible error handling.

Let me know if this helps or if you need a more specific workaround! If your question is answered, feel free to close the issue.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

dosubot[bot] avatar Jul 21 '25 23:07 dosubot[bot]

I think it can be closed

LiMao00 avatar Jul 22 '25 01:07 LiMao00