← Debugging Guides

阅读中文版本

Node.js — error:0308010C digital envelope routines::unsupported

Fix error:0308010C digital envelope routines::unsupported by mapping it to the OpenSSL 3 md4 removal, then upgrade the toolchain or enable the legacy provider deliberately.

advanceddebuggingnodejsopensslbuild

Symptoms

  • error:0308010C:digital envelope routines::unsupported appears during a webpack 4 build after upgrading Node to 17 or later
  • The build fails at the hashing step of an older toolchain (webpack 4, vue-cli 4, react-scripts 4) while the source code is untouched
  • Stack frames point into crypto.createHash with the md4 algorithm

Possible causes

  • Node 17+ bundles OpenSSL 3, which removes legacy algorithms like md4 from the default provider
  • The toolchain hashes content with md4 to generate cache keys and file digests
  • CI moved to a newer Node image while local development stayed on Node 16, so the failure appears only in CI

Diagnosis steps

Confirm the algorithm behind the failure

node -e "require('crypto').createHash('md4')" 2>&1 | head -3

Interpretation

Reproducing the same error on a bare createHash call proves the failure is the runtime crypto policy, not the bundler logic.

Check the Node version boundary

node --version && docker run --rm node:16 node --version 2>/dev/null

Interpretation

A failure on 17+ and success on 16 pins the cause to the OpenSSL 3 transition bundled with Node 17.

Locate the md4 usage in the toolchain

grep -R "md4" node_modules/webpack/lib/util/ | head -5

Interpretation

Finding createHash('md4') inside the installed dependency confirms which layer must be upgraded or worked around.

Root cause

Node 17 and later bundle OpenSSL 3, which moves md4 and other legacy algorithms out of the default provider. The build tooling computes integrity hashes with md4, and createHash throws error:0308010C because the algorithm is unavailable without the legacy provider. The regression arrives with the runtime upgrade, not with any code change.

Fix

Prefer upgrading the toolchain: webpack 5, vue-cli 5, react-scripts 5 all replaced md4 hashing. When an upgrade is not immediately possible, run with NODE_OPTIONS=--openssl-legacy-provider as a scoped, temporary workaround pinned to the build step only, and plan the upgrade with a sunset date.

Risk note

The legacy provider re-enables deprecated, unvalidated crypto paths process-wide. Scope it to the build command, never to production servers, and time-box it.

Verify the fix

Run the full build on the new toolchain without the flag and confirm success; if using the workaround, assert the flag exists only in the build script and document its removal date.

Symptom walkthrough

The hex blob decodes to a specific decision:

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:71:19)

0308010C means the provider layer rejected the requested digest. Reproduce it in one line on Node 18:

node -e "require('crypto').createHash('md4')"
# throws error:0308010C ... unsupported

The same line on Node 16 succeeds. That version pair is the entire story: OpenSSL 3 removed md4 from the default provider, and the installed webpack 4 computes its cache digests with md4. The stack usually lands in webpack/lib/util/createHash.js, naming both the victim and the algorithm.

Fix in practice

The durable fix is upgrading the hash consumer. Webpack 5 switched to xxhash64 and md5 fallbacks; vue-cli 5 and react-scripts 5 inherited the fix. Check the boundary first:

node -e "require('crypto').createHash('md4')" 2>/dev/null && echo ok || echo affected

For the transition period, scope the workaround to the build command only:

{
  "scripts": {
    "build": "NODE_OPTIONS=--openssl-legacy-provider webpack --mode production"
  }
}

Add a CI guard so the flag cannot silently become permanent: a scheduled build that runs without the flag and files an issue while it fails. Do not set NODE_OPTIONS globally in the image, and never apply it to production servers — the flag re-enables deprecated crypto paths for the whole process.

Verification

After upgrading webpack (or the scaffolding tool), run the production build with no NODE_OPTIONS at all and confirm success and stable output hashes across two consecutive builds. If the workaround is still in place, grep the repository for every occurrence of the flag: it must appear only in build scripts, never in runtime Dockerfiles or service definitions. Attach the planned removal date to those scripts so the debt is visible, and let the scheduled no-flag CI job turn red the day the upgrade lands.