{"id":"a09b277da74796bf","repo":"colinhacks/zod","slug":"cannot-specify-both-message-and-error-params","errorCode":null,"errorMessage":"Cannot specify both `message` and `error` params","messagePattern":"Cannot specify both `message` and `error` params","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/util.ts","lineNumber":523,"sourceCode":"        {\n          [k in keyof Omit<T, \"error\" | \"message\">]: T[k];\n        } & (\"error\" extends keyof T\n          ? {\n              error?: Exclude<T[\"error\"], string>;\n              // path?: PropertyKey[] | undefined;\n              // message?: string | undefined;\n            }\n          : unknown)\n      >\n    : never;\n\nexport function normalizeParams<T>(_params: T): Normalize<T> {\n  const params: any = _params;\n\n  if (!params) return {} as any;\n  if (typeof params === \"string\") return { error: () => params } as any;\n  if (params?.message !== undefined) {\n    if (params?.error !== undefined) throw new Error(\"Cannot specify both `message` and `error` params\");\n    params.error = params.message;\n  }\n  delete params.message;\n  if (typeof params.error === \"string\") return { ...params, error: () => params.error } as any;\n  return params;\n}\n\nexport function createTransparentProxy<T extends object>(getter: () => T): T {\n  let target: T;\n  return new Proxy(\n    {},\n    {\n      get(_, prop, receiver) {\n        target ??= getter();\n        return Reflect.get(target, prop, receiver);\n      },\n      set(_, prop, value, receiver) {\n        target ??= getter();","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/util.ts#L505-L541","documentation":"Thrown by `normalizeParams` when a check/error parameter object specifies both `message` and `error`. These are aliases: `message` is the user-friendly string form, `error` is the full callback form (`(iss) => string`). Specifying both is ambiguous about which wins, so Zod rejects it. This fires at definition time whenever params are normalized (on any check, refinement, or schema params).","triggerScenarios":"Passing `{ message: 'bad', error: () => 'bad' }` to `.min(1, {...})`, `.refine(..., { message, error })`, or any schema/check that accepts params. Also from spreading a base params object that already has `error` and then adding `message`.","commonSituations":"Refactoring from `error:` (older API) to `message:` and leaving both; merging param objects via spread where one had `error` and the other added `message`; copy-paste between checks.","solutions":["Use only one: `message` (string) OR `error` (function), never both.","If you have a base params object, delete the stale key before adding the new one: `const p = { ...base }; delete p.error; p.message = 'x';`.","Search the offending call site for `message:` and `error:` appearing together and remove one."],"exampleFix":"// before\nz.string().min(3, { message: 'too short', error: () => 'too short' });\n\n// after\nz.string().min(3, { message: 'too short' });\n// or\nz.string().min(3, { error: () => 'too short' });","handlingStrategy":"validation","validationCode":"function assertSingleParam(p) {\n  if (p && p.message !== undefined && p.error !== undefined) {\n    throw new Error('pass either message or error, not both');\n  }\n}","typeGuard":"function hasBothMessageAndError(p): boolean {\n  return !!p && p.message !== undefined && p.error !== undefined;\n}","tryCatchPattern":"try {\n  schema.min(1, { message, error });\n} catch (e) {\n  if (e instanceof Error && e.message === 'Cannot specify both `message` and `error` params') {\n    // delete one of message/error and retry\n  }\n  throw e;\n}","preventionTips":["Use message (string) OR error (function), never both, in any check/refine params.","When spreading a base params object, delete the stale key before adding the new one.","Lint for objects containing both message and error keys."],"tags":["params","schema-definition","api-misuse"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}