denoland/deno · error · ERR_CRYPTO_INVALID_DIGEST

ERR_CRYPTO_INVALID_DIGEST

ERR_CRYPTO_INVALID_DIGEST

Error message

Invalid digest: ${e}

What it means

In hkdfSync (ext/node/polyfills/internal/crypto/hkdf.ts:186-190) the native op op_node_hkdf is wrapped in try/catch, and any failure is re-thrown as ERR_CRYPTO_INVALID_DIGEST with the original error embedded in the message. Note the asymmetry: the JS-side validateAlgorithm already filtered names not in crypto.getHashes(), so this site fires when a name passes that check but the native HKDF op still rejects it, or when the op fails for another reason (e.g. an unusable key handle). The async hkdf() wraps the same op failure into its callback as the error argument.

Source

Thrown at ext/node/polyfills/internal/crypto/hkdf.ts:189

  salt: any,
  info: any,
  length: number,
) {
  ({ hash, key, salt, info, length } = validateParameters(
    hash,
    key,
    salt,
    info,
    length,
  ));

  hash = StringPrototypeToLowerCase(hash);

  const okm = new Uint8Array(length);
  try {
    op_node_hkdf(hash, key[kHandle], salt, info, okm);
  } catch (e) {
    throw new ERR_CRYPTO_INVALID_DIGEST(e);
  }

  return TypedArrayPrototypeGetBuffer(okm);
}

let hashes: Set<string> | null = null;
function validateAlgorithm(algorithm: string) {
  if (hashes === null) {
    hashes = new SafeSet(getHashes());
  }

  if (!SetPrototypeHas(hashes, algorithm)) {
    throw new ERR_CRYPTO_INVALID_DIGEST(algorithm);
  }
}

return {
  hkdf,

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use a mainstream HMAC digest for HKDF: sha256, sha384, or sha512.
  2. Catch by code and surface the embedded cause: if (e.code === 'ERR_CRYPTO_INVALID_DIGEST') inspect e.message for the wrapped op error.
  3. For the async crypto.hkdf(...), check the callback's err argument rather than expecting a throw.
  4. Verify the digest against a small known-answer vector at startup so unsupported digests fail early.

Example fix

// before
crypto.hkdfSync(digestFromConfig, ikm, salt, info, 32); // op rejects -> ERR_CRYPTO_INVALID_DIGEST(e)

// after
const digest = String(digestFromConfig).toLowerCase();
if (!['sha256', 'sha384', 'sha512'].includes(digest)) {
  throw new Error(`unsupported HKDF digest: ${digestFromConfig}`);
}
crypto.hkdfSync(digest, ikm, salt, info, 32);
Defensive patterns

Strategy: try-catch

Validate before calling

const SAFE = new Set(['sha256', 'sha384', 'sha512']);
if (!SAFE.has(String(digest).toLowerCase())) {
  throw new Error(`hkdf digest '${digest}' is not in the supported set`);
}
crypto.hkdfSync(String(digest).toLowerCase(), ikm, salt, info, 32);

Type guard

function isSafeHkdfDigest(name) {
  return ['sha256', 'sha384', 'sha512'].includes(String(name).toLowerCase());
}

Try / catch

try {
  okm = crypto.hkdfSync(digest, ikm, salt, info, 32);
} catch (e) {
  if (e.code === 'ERR_CRYPTO_INVALID_DIGEST') {
    // e.message embeds the native op failure; fall back or surface clearly
    return fallbackDerivation(digest, ikm, salt, info, 32);
  }
  throw e;
}
// async form: check the callback's err argument, same code

Prevention

When it happens

Trigger: hkdfSync with a hash name that exists in getHashes() but is not usable for HKDF by the native implementation; passing a key whose [kHandle] is not a usable secret-key handle (a KeyObject of the wrong kind); runtime/version differences where the JS allowlist and the native op disagree on supported digests.

Common situations: Switching digest configurations from config files (e.g. 'blake2b-512', XOF names like 'shake256') that hash fine but fail inside the HKDF op; code that ran on one Node/Deno version and hits a native-op mismatch on another; feeding an unexpected KeyObject type through an abstraction layer.

Related errors


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