Error [ERR_OSSL_EVP_UNSUPPORTED]

Fixing "digital envelope routines::unsupported" (ERR_OSSL_EVP_UNSUPPORTED in Node.js)

FIX SUMMARY verified
Applies when
node:18-alpinewebpack 4 / CRAOpenSSL 3 hashing

Verified: reproduced in node:18-alpine, then the ERR_OSSL_EVP_UNSUPPORTED signature was gone after the fix (exit 0).

When npm run build (webpack, Create React App, vue-cli, Angular, …) suddenly starts failing with this error, the cause is almost certainly that the Node version went up.

Error: error:0308010C:digital envelope routines::unsupported

The error carries code: 'ERR_OSSL_EVP_UNSUPPORTED' at the end. A build tool may print it like this instead, but the cause is the same in every case.

Module build failed: Error: error:0308010C:digital envelope routines::unsupported
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ]

If you only need the build to pass right now, adding NODE_OPTIONS=--openssl-legacy-provider is the quick way through. It is a stopgap, though, and should not become permanent. Start by confirming at a glance why it happens.

Check node -v first

This error appears because the major version of the OpenSSL bundled with Node changed.

Node versionBundled OpenSSLOld algorithms such as md4
Node 16.xOpenSSL 1.1.1available by default (no error)
17 and later (18 / 20 / 22 / 24 …)OpenSSL 3.xdisabled by default; using one raises ERR_OSSL_EVP_UNSUPPORTED

(The boundary is that Node 17 moved up to OpenSSL 3. Up to 16.x it was the OpenSSL 1.1.1 line.)

In OpenSSL 3, old ciphers such as md4, RC4, RIPEMD-160 and DES were moved into a “legacy provider” that is no longer loaded by default (md5 stays in the default provider, so it is not a cause of this error). Build tools like webpack use md4 internally to hash their output. That is how you end up with “nothing in the code changed, but the build breaks the moment Node goes to 17 or later”.

The usual shape of it is “it passes on my machine, which is still on Node 16, and fails only for a colleague who upgraded or in CI on a newer image”. Before chasing the cause, look at node -v in the environment that is failing.

Reproduction (minimal)

You do not need a build tool: calling md4 is enough to produce the same error.

// index.cjs
const crypto = require('crypto');

const hash = crypto.createHash('md4');
hash.update('errfix');
console.log(hash.digest('hex'));

Run this on Node 18 and it fails as follows (exit code 1).

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:69:19)
    ...
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'
}

The createHash('md4') line fails because the provider that would supply md4 is not found.

Fix 1: get it running (--openssl-legacy-provider)

If you need the build to pass now, enable the legacy provider explicitly. Not one line of code changes.

# macOS / Linux
export NODE_OPTIONS=--openssl-legacy-provider
npm run build
# Windows PowerShell
$env:NODE_OPTIONS="--openssl-legacy-provider"
npm run build

Putting it directly in the npm script works too.

{
  "scripts": {
    "build": "node --openssl-legacy-provider ./node_modules/.bin/webpack"
  }
}

The reproduction above also stops failing when run as node --openssl-legacy-provider index.cjs: it prints the hash and exits with code 0. Not a character of the code changed — only the flag was added.

How it works: providers in OpenSSL 3

OpenSSL 3 split its algorithms into units called providers. The one loaded by default is the default provider, which holds only current, safe algorithms. Older ones such as md4 moved to the legacy provider and cannot be used unless it is enabled explicitly.

--openssl-legacy-provider is the flag that loads that legacy provider at startup. With it, md4 works again and the build tool’s hashing goes through.

Fix 2: the permanent one (get to where the flag can come off)

--openssl-legacy-provider is a flag that deliberately brings back ciphers that were disabled. md4 and RC4 were dropped from the default because they are weak. It works, but take the flag off if you can. The permanent fix is one of these.

  • Upgrade the build tool to a version that supports Node 17+. This is the surest one. For webpack itself, 5.61.0 or later (that version switched its hashing to an implementation that does not depend on OpenSSL, so it no longer fails on Node 17+). For Create React App, move react-scripts to v5 (which pulls in webpack ^5.64.4). Note that webpack v5’s default hash is still md4, so read this as “upgrade to a version that supports Node 17+”, not “v5 fixes it unconditionally”. If you need to, you can also set output.hashFunction: 'xxhash64' explicitly.
  • If your own code uses md4, replace it with an algorithm in OpenSSL 3’s default provider, such as sha256. If the purpose is generating a unique key where collision resistance does not matter, the swap is harmless — but do check the effects of the hash value changing: the length changes, stored IDs and file names may no longer match, and caches get regenerated once.
  • If there is a real reason you cannot upgrade Node, staying on Node 16.x (which bundles OpenSSL 1.1.1) works in the short term. Node 16 is already end-of-life, though, so this too only postpones the problem.

The order is: get the build passing with fix 1, then upgrade the tool with fix 2 and delete the flag. If you are keeping the flag, decide when it comes off before you keep it.

If it still doesn’t work

  • The flag changed nothing: usually it is not reaching the actual build process. If the build goes through another script in package.json, or is started as a child process, check that NODE_OPTIONS is inherited by that process.
  • It happened in Vite or esbuild rather than webpack or CRA: same cause (something is using a cipher OpenSSL 3 disabled). The approach does not change — get running with fix 1, then upgrade that tool and drop the flag.
  • It happens only in CI: CI is often on 17 or later while your machine is still on Node 16. Line up node -v on both so you are reproducing the same thing.
  • Do not make the flag a permanent environment variable: putting NODE_OPTIONS=--openssl-legacy-provider in a shell profile (.bashrc and friends) brings the disabled weak ciphers back for every Node process you run. Pass it to that one build command.

Verification (machine-verified)

This fix was reproduced inside the version-pinned node:18-alpine container, and the ERR_OSSL_EVP_UNSUPPORTED signature was then machine-checked to be gone after the fix.

verify — run-case.mjs
$ node run-case.mjs node/err-ossl-evp-unsupported
● reproduce ERR_OSSL_EVP_UNSUPPORTED present ✓
● apply fix exit 0
● re-run ERR_OSSL_EVP_UNSUPPORTED gone ✓
PASS verified · node:18-alpine · signature gone

That check covers the image above and nothing else. If the fix did not work in your environment, or something here is wrong, send a report (the article and the verified image go into the subject and body).