denoland/deno · error · NodeTypeError

ERR_CRYPTO_INVALID_DIGEST

ERR_CRYPTO_INVALID_DIGEST

Error message

Invalid digest: ${digest}

What it means

After pbkdf2 lowercases the digest string and forwards it to the native op, a digest the crypto backend does not recognize makes op_node_pbkdf2 return false and the JS layer throws ERR_CRYPTO_INVALID_DIGEST. digest must be a string naming a known digest algorithm (e.g., 'sha256', 'sha384', 'sha512', 'md5'); note the argument is validated as a string earlier, so this error is specifically about unknown names, not wrong types.

Source

Thrown at ext/node/polyfills/internal/crypto/pbkdf2.ts:95

  password: any,
  salt: any,
  iterations: number,
  keylen: number,
  digest: string,
): Buffer {
  ({ password, salt, iterations, keylen, digest } = check(
    password,
    salt,
    iterations,
    keylen,
    digest,
  ));

  digest = StringPrototypeToLowerCase(digest);

  const DK = new Uint8Array(keylen);
  if (!op_node_pbkdf2(password, salt, iterations, digest, DK)) {
    throw new ERR_CRYPTO_INVALID_DIGEST(digest);
  }

  return Buffer.from(DK);
}

/**
 * @param iterations Needs to be higher or equal than zero
 * @param keylen  Needs to be higher or equal than zero but less than max allocation size (2^30)
 * @param digest Algorithm to be used for encryption
 */
function pbkdf2(
  password: any,
  salt: any,
  iterations: number,
  keylen: number,
  digest: string,
  callback: (err: Error | null, derivedKey?: Buffer) => void,
) {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use a canonical lowercase name such as 'sha256', 'sha384' or 'sha512'
  2. Validate digest against crypto.getHashes() before calling pbkdf2
  3. Set an explicit default digest in your config layer instead of letting it fall through to undefined/''

Example fix

// before
const dk = crypto.pbkdf2Sync(pw, salt, iterations, 32, cfg.hash); // cfg.hash = 'sha356' -> throws

// after
const digest = crypto.getHashes().includes(cfg.hash) ? cfg.hash : 'sha256';
const dk = crypto.pbkdf2Sync(pw, salt, iterations, 32, digest);
Defensive patterns

Strategy: validation

Validate before calling

if (typeof digest !== 'string' || !crypto.getHashes().includes(digest)) {
  throw new Error(`unsupported pbkdf2 digest: ${String(digest)}`);
}
crypto.pbkdf2Sync(password, salt, iterations, keylen, digest);

Type guard

function isSupportedDigest(name: string): boolean {
  return crypto.getHashes().includes(name);
}

Try / catch

try {
  crypto.pbkdf2Sync(password, salt, iterations, keylen, digest);
} catch (e) {
  if (e?.code === 'ERR_CRYPTO_INVALID_DIGEST') {
    crypto.pbkdf2Sync(password, salt, iterations, keylen, 'sha256'); // explicit fallback
  } else throw e;
}

Prevention

When it happens

Trigger: crypto.pbkdf2Sync(pw, salt, 100000, 32, 'sha5123') — a misspelled, empty, or unsupported digest name reaches the native digest lookup and fails; same for the async crypto.pbkdf2 form.

Common situations: Digest names copied from another library's enum or a WebCrypto constant that does not map to a native name; typos in configuration ('sha356', 'sha-2'); an optional digest config field left as empty string and defaulted through.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e3d6a71ff8fc7d16. Report an issue: GitHub.