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

  1. Use one of the supported pairs: algorithm in {md5, sha1, sha256, sha384, sha512} and encoding in {hex, base64, base64url}.
  2. For an unsupported algorithm, register a custom string format with z.stringFormat() (or config.z.stringFormat) supplying your own RegExp instead of z.hash().
  3. 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

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


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)