{"record":{"id":"8bac5bdaa5d48083","repo":"denoland/deno","slug":"err-crypto-hash-finalized","errorCode":"ERR_CRYPTO_HASH_FINALIZED","errorMessage":"Digest already called","messagePattern":"Digest already called","errorType":"exception","errorClass":"ERR_CRYPTO_HASH_FINALIZED","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/hash.ts","lineNumber":73,"sourceCode":"  isArrayBufferView,\n} = core.loadExtScript(\"ext:deno_node/internal/util/types.ts\");\n\nconst {\n  FunctionPrototypeCall,\n  ObjectPrototypeIsPrototypeOf,\n  ObjectSetPrototypeOf,\n  ReflectApply,\n  SafeArrayIterator,\n  StringFromCharCode,\n  StringPrototypeToLowerCase,\n  Symbol,\n  TypedArrayPrototypeGetByteLength,\n  Uint8Array,\n  Uint8ArrayPrototype,\n} = primordials;\n\nfunction unwrapErr(ok: boolean) {\n  if (!ok) throw new ERR_CRYPTO_HASH_FINALIZED();\n}\n\nconst kHandle = Symbol(\"kHandle\");\nconst kFinalized = Symbol(\"kFinalized\");\n\nlet warnedShakeOutputLength = false;\n\nfunction Hash(\n  algorithm: string | Hasher,\n  options?: { outputLength?: number },\n): Hash {\n  if (!ObjectPrototypeIsPrototypeOf(Hash.prototype, this)) {\n    return new Hash(algorithm, options);\n  }\n  const isCopy = ObjectPrototypeIsPrototypeOf(Hasher.prototype, algorithm);\n  if (!isCopy) {\n    validateString(algorithm, \"algorithm\");\n  }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/hash.ts#L55-L91","documentation":"Hash.update() funnels its native op results through unwrapErr(): when op_node_hash_update / op_node_hash_update_str returns false, the hash handle can no longer accept data and ERR_CRYPTO_HASH_FINALIZED ('Digest already called') is thrown. A hash is single-shot — once digest() consumes it, update() on the same object is illegal.","triggerScenarios":"const h = crypto.createHash('sha256'); h.digest('hex'); h.update('more'); — any update after digest. Common in streams when a final chunk arrives after the hash object was finalized, or when a helper digests early for logging and the caller keeps updating.","commonSituations":"Reusing one Hash instance across requests or loop iterations; middleware that computes an intermediate digest for debug logging; piping a stream where 'end' handling digests the hash before a late write.","solutions":["Create a fresh crypto.createHash(algorithm) for every digest you need — Hash objects are cheap and not reusable","If you need the running state later, call h.copy() BEFORE digest() and digest the copy: const h2 = h.copy(); h2.digest('hex')","Remove intermediate digest() calls used for logging, or route them through a copy"],"exampleFix":"// before\nconst h = crypto.createHash('sha256');\nh.update(chunk1);\nconsole.log(h.digest('hex')); // finalized\nh.update(chunk2); // throws\n\n// after\nconst h = crypto.createHash('sha256');\nh.update(chunk1);\nconst h2 = h.copy();\nconsole.log(h2.digest('hex')); // digest the copy\nh.update(chunk2);","handlingStrategy":"validation","validationCode":"// Own the lifecycle: one Hash per digest, copy before consuming.\nclass SafeHash {\n  #h = crypto.createHash('sha256');\n  #done = false;\n  update(data: string | Buffer) {\n    if (this.#done) throw new Error('SafeHash already digested');\n    this.#h.update(data);\n    return this;\n  }\n  snapshot() { return this.#done ? null : this.#h.copy(); }\n  digest(enc?: string) { this.#done = true; return this.#h.digest(enc); }\n}","typeGuard":null,"tryCatchPattern":"catch (e) { if ((e as NodeJS.ErrnoException).code === 'ERR_CRYPTO_HASH_FINALIZED') { /* start a fresh createHash and re-feed the buffered input */ } throw e; }","preventionTips":["Create a new Hash per digest instead of reusing instances","copy() before digest() when the running state must survive","Remove debug/logging code that digests early"],"tags":["crypto","hash","stream-lifecycle","node-compat"],"backgroundTag":"hash-digest-already-called","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}