Node.js "ERR_OSSL_EVP_UNSUPPORTED" — Old Crypto in New Node (Webpack Classic)

Node 17+ ships OpenSSL 3, which removed the legacy MD4 hash webpack (and some older tooling) uses. One env var unblocks you today; the real fix is upgrading the toolchain.

What you'll see

Root causes

OpenSSL 3 legacy provider needed for MD4

Webpack 4's default hashing (MD4) was removed from OpenSSL 3's default provider. Node 17+ therefore throws on hash creation. NODE_OPTIONS=--openssl-legacy-provider re-enables the legacy provider.

Fix it

  1. Confirm the Node version boundary
    node -v ; # 16.x works, 17+ fails = OpenSSL 3 boundary
  2. Unblock with the legacy provider
    export NODE_OPTIONS=--openssl-legacy-provider && npm run build
  3. Make it stick in package.json
    "scripts": { "build": "NODE_OPTIONS=--openssl-legacy-provider webpack" }   # cross-platform: cross-env
  4. The real fix: upgrade the toolchain
    npm i webpack@5 --save-dev 2>/dev/null ; # or upgrade react-scripts/vue-cli to the OpenSSL-3-safe major

Field note

--openssl-legacy-provider reintroduces weak crypto for the build only — acceptable as a bridge, not as a permanent posture. Docker/CI: pin node:16 while you plan the webpack 5 migration; pinning is honest, env-flag hacks in five places are not.

Common questions

Is the legacy-provider flag safe?

For build-time hashing: yes, pragmatically. It doesn't affect your app's runtime TLS. Treat it as scaffolding until webpack 5/upgraded tooling removes the need.

Why does CI pass but local fail (or vice versa)?

Different Node versions across environments: CI pins 16, your machine runs 20. Align versions (.nvmrc / engines) so the flag becomes unnecessary everywhere at once.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.