{"record":{"id":"e8b2fe17f5c93dc0","repo":"denoland/deno","slug":"err-crypto-invalid-digest","errorCode":"ERR_CRYPTO_INVALID_DIGEST","errorMessage":"Invalid digest: ${e}","messagePattern":"Invalid digest: (.+?)","errorType":"exception","errorClass":"ERR_CRYPTO_INVALID_DIGEST","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/hkdf.ts","lineNumber":189,"sourceCode":"  salt: any,\n  info: any,\n  length: number,\n) {\n  ({ hash, key, salt, info, length } = validateParameters(\n    hash,\n    key,\n    salt,\n    info,\n    length,\n  ));\n\n  hash = StringPrototypeToLowerCase(hash);\n\n  const okm = new Uint8Array(length);\n  try {\n    op_node_hkdf(hash, key[kHandle], salt, info, okm);\n  } catch (e) {\n    throw new ERR_CRYPTO_INVALID_DIGEST(e);\n  }\n\n  return TypedArrayPrototypeGetBuffer(okm);\n}\n\nlet hashes: Set<string> | null = null;\nfunction validateAlgorithm(algorithm: string) {\n  if (hashes === null) {\n    hashes = new SafeSet(getHashes());\n  }\n\n  if (!SetPrototypeHas(hashes, algorithm)) {\n    throw new ERR_CRYPTO_INVALID_DIGEST(algorithm);\n  }\n}\n\nreturn {\n  hkdf,","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/hkdf.ts#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a mainstream HMAC digest for HKDF: sha256, sha384, or sha512.","Catch by code and surface the embedded cause: if (e.code === 'ERR_CRYPTO_INVALID_DIGEST') inspect e.message for the wrapped op error.","For the async crypto.hkdf(...), check the callback's err argument rather than expecting a throw.","Verify the digest against a small known-answer vector at startup so unsupported digests fail early."],"exampleFix":"// before\ncrypto.hkdfSync(digestFromConfig, ikm, salt, info, 32); // op rejects -> ERR_CRYPTO_INVALID_DIGEST(e)\n\n// after\nconst digest = String(digestFromConfig).toLowerCase();\nif (!['sha256', 'sha384', 'sha512'].includes(digest)) {\n  throw new Error(`unsupported HKDF digest: ${digestFromConfig}`);\n}\ncrypto.hkdfSync(digest, ikm, salt, info, 32);","handlingStrategy":"try-catch","validationCode":"const SAFE = new Set(['sha256', 'sha384', 'sha512']);\nif (!SAFE.has(String(digest).toLowerCase())) {\n  throw new Error(`hkdf digest '${digest}' is not in the supported set`);\n}\ncrypto.hkdfSync(String(digest).toLowerCase(), ikm, salt, info, 32);","typeGuard":"function isSafeHkdfDigest(name) {\n  return ['sha256', 'sha384', 'sha512'].includes(String(name).toLowerCase());\n}","tryCatchPattern":"try {\n  okm = crypto.hkdfSync(digest, ikm, salt, info, 32);\n} catch (e) {\n  if (e.code === 'ERR_CRYPTO_INVALID_DIGEST') {\n    // e.message embeds the native op failure; fall back or surface clearly\n    return fallbackDerivation(digest, ikm, salt, info, 32);\n  }\n  throw e;\n}\n// async form: check the callback's err argument, same code","preventionTips":["Pin HKDF digests to sha256/sha384/sha512.","For async crypto.hkdf, always handle the callback error - it never throws this directly.","Run a known-answer HKDF test at startup to catch runtime digest mismatches early."],"tags":["crypto","hkdf","digest-algorithm","node-compat","error-wrapping"],"backgroundTag":"unsupported-hash-algorithm","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}