Utilities common patterns
Keep invalid input out of logs by default
zodErrorToStructuredLog accepts the rejected input as an optional second argument. Omit it unless the log destination, retention policy, and data classification permit the payload.
Fragment inside an if (!parsed.success) branch; logger is the application's structured logger:
const event = zodErrorToStructuredLog(parsed.error);
logger.info(event, "request rejected");
If the input is useful for diagnosis, pass a redacted projection rather than the original boundary value.
Fragment inside an if (!parsed.success) branch, after input has been narrowed to Record<string, unknown>; logger is the application's structured logger:
const safeInput = {
emailDomain:
typeof input.email === "string" ? input.email.split("@")[1] : undefined,
suppliedFields: Object.keys(input),
};
logger.info(
zodErrorToStructuredLog(parsed.error, safeInput),
"request rejected",
);
Select text or structure at the final boundary
Use zodErrorToString for a CLI message or compact diagnostic. Use zodErrorToStructuredLog when log processors need fields such as issueCount, path, or code.
Fragment where error is a ZodError, format is the caller's output choice, and logger is the application's structured logger:
if (format === "text") {
process.stderr.write(`${zodErrorToString(error)}\n`);
} else {
logger.error(zodErrorToStructuredLog(error));
}
Neither function changes the ZodError, maps errors into Altstack Result values, or selects an HTTP status. Those decisions belong to the caller.
Preserve Zod's issue order
Both formatters iterate error.issues in its existing order. If consumers require a different sort or grouping, transform the returned issues array after formatting rather than assuming it is grouped by path.
See also
Utilities API Documentation describes every property and the exact path normalization.