colinhacks/zod · error · Error
Unrecognized hash format
Error message
Unrecognized hash format: ${format} What it means
Thrown by z.hash(alg, params) when the constructed format key `${alg}_${enc}` does not resolve to an entry in core.regexes. Only the five algorithms md5/sha1/sha256/sha384/sha512 crossed with the three encodings hex/base64/base64url are predefined (15 keys). Any other combination — a typo, a future algorithm, or a custom encoding — has no matching regex and is rejected at schema-construction time.
Solutions
- Use one of the supported pairs: algorithm in {md5, sha1, sha256, sha384, sha512} and encoding in {hex, base64, base64url}.
- For an unsupported algorithm, register a custom string format with z.stringFormat() (or config.z.stringFormat) supplying your own RegExp instead of z.hash().
- If the value comes from config/user input, validate it against the allowed set before passing it to z.hash().
Example fix
// before (throws — sha3 not registered)
const h = z.hash('sha3_256');
// after (supported algorithm)
const h = z.hash('sha256');
// or: register a custom format for an unsupported algorithm
z.stringFormat('sha3_256', /^[0-9a-fA-F]{64}$/); Defensive patterns
Strategy: validation
Validate before calling
const HASH_ALGS = ['md5', 'sha1', 'sha256', 'sha384', 'sha512'];
const HASH_ENCODINGS = ['hex', 'base64', 'base64url'];
function assertHashFormat(alg, enc = 'hex') {
if (!HASH_ALGS.includes(alg) || !HASH_ENCODINGS.includes(enc)) {
throw new Error(`Unsupported hash format: ${alg}_${enc}`);
}
}
assertHashFormat(userAlg, userEnc);
const Schema = z.hash(userAlg, { enc: userEnc }); Type guard
function isHashAlgorithm(v) {
return typeof v === 'string' && ['md5', 'sha1', 'sha256', 'sha384', 'sha512'].includes(v);
} Try / catch
try {
const Schema = z.hash(alg, { enc });
} catch (e) {
if (e.message.startsWith('Unrecognized hash format')) {
// fall back to a registered custom stringFormat or reject the input
throw new Error(`Unsupported hash format '${alg}_${enc}'; supported: md5/sha1/sha256/sha384/sha512 x hex/base64/base64url`);
}
throw e;
} Prevention
- If the algorithm/encoding come from config or user input, validate against the fixed allow-list before calling z.hash().
- In TypeScript, avoid casting to `as any`; let the HashAlgorithm/HashEncoding union types catch typos at compile time.
- Keep a unit test enumerating every supported pair so regressions surface early.
When it happens
Trigger: Calling z.hash('sha128') or z.hash('sha256', { enc: 'utf8' }). Using a string variable typed loosely (via `as any` or plain JS) so the compiler cannot catch an invalid algorithm/encoding pair.
Common situations: Assuming blake2/argon2/sha3 are supported because they exist in other libraries. Copying an algorithm name from a hash output label that differs from the registry key. JavaScript (non-TS) callers passing arbitrary strings.
Related errors
- Unrecognized hash format
- Cannot create literal schema with no valid values
- Invalid UUID version
- A discriminator value for key
- Can't use "invalid_type_error" or "required_error" in…
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/a9e5456a5222c736.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/classic/schemas.ts:1022
export function hostname(_params?: string | core.$ZodStringFormatParams): ZodCustomStringFormat<"hostname"> {
return core._stringFormat(ZodCustomStringFormat, "hostname", core.regexes.hostname, _params) as any;
}
export function hex(_params?: string | core.$ZodStringFormatParams): ZodCustomStringFormat<"hex"> {
return core._stringFormat(ZodCustomStringFormat, "hex", core.regexes.hex, _params) as any;
}
export function hash<Alg extends util.HashAlgorithm, Enc extends util.HashEncoding = "hex">(
alg: Alg,
params?: {
enc?: Enc;
} & core.$ZodStringFormatParams
): ZodCustomStringFormat<`${Alg}_${Enc}`> {
const enc = params?.enc ?? "hex";
const format = `${alg}_${enc}` as const;
const regex = core.regexes[format as keyof typeof core.regexes] as RegExp;
if (!regex) throw new Error(`Unrecognized hash format: ${format}`);
return core._stringFormat(ZodCustomStringFormat, format, regex, params) as any;
}
// ZodNumber
export interface _ZodNumber<Internals extends core.$ZodNumberInternals = core.$ZodNumberInternals>
extends _ZodType<Internals> {
gt(value: number, params?: string | core.$ZodCheckGreaterThanParams): this;
/** Identical to .min() */
gte(value: number, params?: string | core.$ZodCheckGreaterThanParams): this;
min(value: number, params?: string | core.$ZodCheckGreaterThanParams): this;
lt(value: number, params?: string | core.$ZodCheckLessThanParams): this;
/** Identical to .max() */
lte(value: number, params?: string | core.$ZodCheckLessThanParams): this;
max(value: number, params?: string | core.$ZodCheckLessThanParams): this;
/** Consider `z.int()` instead. This API is considered *legacy*; it will never be removed but a better alternative exists. */
int(params?: string | core.$ZodCheckNumberFormatParams): this;
/** @deprecated This is now identical to `.int()`. Only numbers in the safe integer range are accepted. */
safe(params?: string | core.$ZodCheckNumberFormatParams): this;View on GitHub (pinned to 2d90846af9)