NODE_OPTIONS=--openssl-legacy-provider npm start (re-enables legacy algorithms). The permanent fix is upgrading to Webpack 5, react-scripts v5 (Create React App), or Angular CLI 13+ — all of which implement MD4 in JavaScript and no longer call OpenSSL for it.
What is ERR_OSSL_EVP_UNSUPPORTED?
ERR_OSSL_EVP_UNSUPPORTED is a Node.js error code that wraps an OpenSSL error.
The full string users see is:
Error: error:0308010C:digital envelope routines::unsupported
The hex code 0308010C is an OpenSSL error identifier: library 3 (EVP — envelope
encryption), reason 0x10C (algorithm not supported). OpenSSL 3.0 introduced a new provider
architecture that disabled several legacy algorithms — including MD4 — by
default. Webpack 4's default hash function for module IDs and chunk names is MD4. When
Webpack 4 calls Node.js's crypto.createHash('md4'), OpenSSL 3.0 refuses and
throws ERR_OSSL_EVP_UNSUPPORTED.
The error is documented in the Node.js API errors reference.
Error: error:0308010C:digital envelope routines::unsupportederror:0308010c:digital envelope routines::unsupportedopensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ]ERR_OSSL_EVP_UNSUPPORTEDnpm ERR! code ERR_OSSL_EVP_UNSUPPORTED
Full Error Example
$ npm start
> my-react-app@0.1.0 start
> react-scripts start
node:internal/crypto/hash:71
this[kHandle] = new Hash(algorithm, xofLen);
^
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:130:10)
at module.exports (/project/node_modules/webpack/lib/util/createHash.js:135:53)
at NormalModule._initBuildHash (/project/node_modules/webpack/lib/NormalModule.js:417:16)
at handleParseError (/project/node_modules/webpack/lib/NormalModule.js:471:10)
at /project/node_modules/webpack/lib/NormalModule.js:503:5
at /project/node_modules/webpack/lib/NormalModule.js:358:12
at /project/node_modules/loader-runner/lib/LoaderRunner.js:373:3 {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
The error object includes these diagnostic fields:
| Field | Value | Meaning |
|---|---|---|
code | 'ERR_OSSL_EVP_UNSUPPORTED' | The Node.js error code wrapping the OpenSSL failure |
library | 'digital envelope routines' | The OpenSSL subsystem that rejected the algorithm |
reason | 'unsupported' | OpenSSL 3.0 does not support the requested algorithm in its default provider |
opensslErrorStack | ['error:03000086:...'] | The inner OpenSSL initialization failure that caused the outer error |
Node.js Version Matrix
| Node.js version | OpenSSL version | MD4 available by default? | ERR_OSSL_EVP_UNSUPPORTED possible? |
|---|---|---|---|
| Node.js 14.x (LTS until Apr 2023) | OpenSSL 1.1.1 | Yes | No |
| Node.js 16.x (LTS until Sep 2023) | OpenSSL 1.1.1 | Yes | No |
| Node.js 17.x (Current, EOL) | OpenSSL 3.0 | No | Yes |
| Node.js 18.x (LTS until Apr 2025) | OpenSSL 3.0 | No | Yes |
| Node.js 20.x (LTS until Apr 2026) | OpenSSL 3.0 | No | Yes |
| Node.js 22.x (LTS, current) | OpenSSL 3.0 | No | Yes |
All Causes at a Glance
| Cause | Typical symptom | Fix |
|---|---|---|
| Webpack 4 default MD4 hash on Node.js 17+ | npm start / npm run build crashes immediately | --openssl-legacy-provider or upgrade to Webpack 5 |
| Create React App with react-scripts < 5 | CRA dev server or build fails on Node.js 17+ | Upgrade react-scripts to v5.0.1+ |
| Angular CLI 11–12 (Webpack 4 internally) | ng serve or ng build crashes | Upgrade to Angular 13+ or use --openssl-legacy-provider |
| Vue CLI with Webpack 4 | vue-cli-service serve crashes | --openssl-legacy-provider or migrate to Vite |
| Storybook < 7 with Webpack 4 | npm run storybook crashes | Upgrade Storybook to v7+ or use --openssl-legacy-provider |
| node-sass (libsass bindings) | Sass compilation step throws the error | Replace node-sass with sass (Dart Sass) |
Custom crypto.createHash('md4') call | App-level code throws at the hash call | Replace with 'sha256' or another supported algorithm |
| CI/Docker on new Node.js base image | Works locally (Node 16), fails in CI (Node 18+) | Align Node.js versions or add NODE_OPTIONS to CI env |
Cause 1 – Webpack 4 Default MD4 Hash
Webpack 4 uses MD4 as its default hash algorithm for generating module IDs, chunk names, and
content hashes. The call originates deep inside Webpack's createHash.js utility,
which delegates to Node.js's built-in crypto.createHash('md4'). On Node.js 17+
with OpenSSL 3.0, this call fails immediately.
Webpack 5 (released October 2020) replaced this by shipping its own MD4 implementation in
pure JavaScript (webpack/lib/util/Hash.js). It never calls
crypto.createHash('md4'), so OpenSSL 3.0 is never involved.
# The call chain that throws:
# webpack/lib/util/createHash.js → crypto.createHash('md4') → OpenSSL 3.0 rejects it
# Verify which webpack version you have:
npx webpack --version
# or
cat node_modules/webpack/package.json | grep '"version"'
Cause 2 – Create React App with react-scripts < 5
Create React App pins its internal Webpack version. react-scripts versions 1–4
all use Webpack 4, so any CRA project not yet upgraded to react-scripts@5 will
throw ERR_OSSL_EVP_UNSUPPORTED on Node.js 17+.
# Check your current react-scripts version:
cat node_modules/react-scripts/package.json | grep '"version"'
# Affected: react-scripts 1.x, 2.x, 3.x, 4.x (all use Webpack 4)
# Safe: react-scripts 5.0.0+ (uses Webpack 5)
Cause 3 – Angular CLI 11 or 12
Angular CLI switched from Webpack 4 to Webpack 5 in Angular 13 (November 2021). Projects on Angular 11 or 12 use Webpack 4 internally and hit this error on Node.js 17+. Angular 13+ is fully unaffected.
# Check Angular CLI version:
ng version
# Affected: @angular/cli 11.x, 12.x (Webpack 4)
# Safe: @angular/cli 13.x and above (Webpack 5)
Cause 4 – Vue CLI with Webpack 4 (vue-cli-service)
Vue CLI projects created with @vue/cli before the Vue 3 / Vite era use
Webpack 4 via vue-cli-service. Running npm run serve or
npm run build on Node.js 17+ throws ERR_OSSL_EVP_UNSUPPORTED.
# Check vue-cli-service webpack version:
cat node_modules/@vue/cli-service/package.json | grep '"webpack"'
# If webpack: "^4.x.x" — you are affected. Apply the workaround or migrate to Vite.
Cause 5 – Storybook < 7 / Other Webpack 4 Tools
Any tool that vendor-bundles Webpack 4 is affected: Storybook 5–6, Gatsby v3 and earlier, Next.js v10 and earlier, and custom Webpack 4 configs. Storybook v7+ and Gatsby v4+ all moved to Webpack 5.
# Storybook version check:
cat node_modules/@storybook/core/package.json | grep '"version"'
# Gatsby version check:
cat node_modules/gatsby/package.json | grep '"version"'
Fix 1 – Quick Workaround: NODE_OPTIONS=--openssl-legacy-provider
The --openssl-legacy-provider flag tells OpenSSL 3.0 to load its legacy provider,
which re-enables MD4 and other deprecated algorithms. This unblocks Webpack 4 immediately
without any code changes.
macOS / Linux (bash/zsh — single session)
export NODE_OPTIONS=--openssl-legacy-provider
npm start
# or in one line:
NODE_OPTIONS=--openssl-legacy-provider npm start
Windows Command Prompt (CMD)
set NODE_OPTIONS=--openssl-legacy-provider
npm start
Windows PowerShell
$env:NODE_OPTIONS="--openssl-legacy-provider"
npm start
Cross-platform: add to package.json scripts with cross-env (recommended)
# Install cross-env once:
npm install --save-dev cross-env
# Then update package.json scripts:
{
"scripts": {
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts start",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts build",
"test": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts test",
"storybook": "cross-env NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6006",
"ng": "cross-env NODE_OPTIONS=--openssl-legacy-provider ng"
}
}
Persist via .npmrc (applies to all npm commands in the project)
# Create or edit .npmrc in the project root:
node-options=--openssl-legacy-provider
# This is equivalent to setting NODE_OPTIONS for every npm run command.
# Commit this file to source control so all contributors get the same behavior.
--openssl-legacy-provider re-enables MD4 and other
cryptographic algorithms that OpenSSL 3.0 disabled because they are considered weak. Apply this
flag only to build/dev scripts, never to a production Node.js server that
handles HTTP requests or user data. Use it as a temporary bridge while you plan the upgrade to
Webpack 5.
Fix 2 – Proper Fix for Create React App: Upgrade react-scripts to v5
react-scripts@5.0.0 (January 2022) upgraded CRA's internal Webpack from 4 to 5.
This is the recommended permanent fix for all CRA projects.
# Step 1: update react-scripts
npm install --save-exact react-scripts@5.0.1
# Step 2: clean install to avoid stale Webpack 4 packages in node_modules
rm -rf node_modules package-lock.json
npm install
# Step 3: verify — npm start should now work on Node.js 18/20/22 without NODE_OPTIONS
npm start
react-scripts@5, you may see new ESLint
warnings or TypeScript errors. The Webpack 5 upgrade also changed how some environment
variables and polyfills work. Review the
CRA v5 changelog
for breaking changes. Also remove any NODE_OPTIONS=--openssl-legacy-provider from
your scripts after the upgrade — it is no longer needed.
Fix 3 – Proper Fix for Angular: Upgrade to Angular 13+
Angular CLI 13 (November 2021) migrated to Webpack 5. The Angular team provides
ng update to automate the migration across major versions.
# From Angular 12 to 13 (do one major version at a time):
ng update @angular/cli@13 @angular/core@13
# Verify the migration succeeded — ng serve should work without NODE_OPTIONS:
ng serve
# If you are on Angular 11, first update to 12, then to 13:
ng update @angular/cli@12 @angular/core@12
ng update @angular/cli@13 @angular/core@13
Consult the official Angular update guide at update.angular.io for a step-by-step checklist tailored to your specific version jump.
Fix 4 – Proper Fix for Plain Webpack Projects: Upgrade to Webpack 5
If your project uses Webpack directly (not via CRA or Angular CLI), upgrade
webpack and webpack-cli to v5. Webpack 5 made many breaking changes
— review the
official Webpack 5 migration guide.
# Install Webpack 5:
npm install --save-dev webpack@5 webpack-cli@5
# Key Webpack 5 breaking changes to check:
# 1. Node.js core module polyfills removed — add them explicitly if needed
# 2. Module Federation is now built in
# 3. Output.hashFunction defaults to 'xxhash64' (not md4) on Node.js 17+
# 4. Asset modules replace file-loader, url-loader, raw-loader
# If you need to keep md4 compatible hashes (e.g. deterministic chunk names):
# webpack.config.js
module.exports = {
output: {
hashFunction: 'sha256', // or 'xxhash64' for speed
},
};
# Verify:
npx webpack --version
# Expected: webpack 5.x.x
Fix 5 – Vue CLI Projects: Use --openssl-legacy-provider or Migrate to Vite
Vue CLI does not have a built-in path to Webpack 5 as clean as CRA or Angular CLI. The
recommended modern approach for new Vue 3 projects is Vite. For existing Vue CLI projects,
use the cross-env workaround until a Vite migration is feasible.
# Short-term: add cross-env to vue-cli scripts
# package.json
{
"scripts": {
"serve": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build"
}
}
# Long-term: migrate to Vite
# https://vitejs.dev/guide/migration-from-v2.html
Fix 6 – Replace node-sass with sass (Dart Sass)
node-sass (libsass bindings) is deprecated and also triggers
ERR_OSSL_EVP_UNSUPPORTED via its native gyp build pipeline on newer Node.js.
Replace it with sass (Dart Sass), which is the actively maintained successor.
# Remove node-sass:
npm uninstall node-sass
# Install sass (Dart Sass — pure JS, no native bindings):
npm install --save-dev sass
# In CRA: sass is all you need; react-scripts automatically picks it up.
# In Webpack: update sass-loader to use 'sass' instead of 'node-sass':
# webpack.config.js
{
loader: 'sass-loader',
options: {
implementation: require('sass'), // or omit — sass-loader auto-detects
}
}
Fix 7 – App Code Using crypto.createHash('md4') Directly
If the stack trace points to your own application code (not Webpack internals), you have a
direct call to crypto.createHash('md4'). Replace it with a supported algorithm.
// Wrong — MD4 is not available in OpenSSL 3.0 without the legacy provider
const crypto = require('crypto');
const hash = crypto.createHash('md4').update(data).digest('hex');
// Fix — use SHA-256 (strongly recommended for security) or SHA-1 (if you need short hashes)
const hash256 = crypto.createHash('sha256').update(data).digest('hex');
const hash1 = crypto.createHash('sha1').update(data).digest('hex');
// If you must maintain MD4 output for legacy compatibility, use a pure-JS implementation:
// npm install md4 (or npm install spark-md5)
const SparkMD4 = require('spark-md5');
const md4hash = SparkMD4.hash(data);
Fix 8 – Docker and CI Environments
CI/CD pipelines and Docker images frequently use the latest Node.js LTS base image, which ships with OpenSSL 3.0. This is why the error appears in CI but not on a developer's machine running Node.js 16.
Dockerfile — short-term workaround
FROM node:20-alpine
WORKDIR /app
# Set legacy provider for the build step only
ENV NODE_OPTIONS=--openssl-legacy-provider
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# For the runtime stage, do NOT carry NODE_OPTIONS into production
FROM node:20-alpine
WORKDIR /app
COPY --from=0 /app/build ./build
COPY --from=0 /app/node_modules ./node_modules
# NODE_OPTIONS is not set here — good
CMD ["node", "server.js"]
GitHub Actions
# .github/workflows/build.yml
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_OPTIONS: --openssl-legacy-provider # workaround for Webpack 4
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
GitLab CI
# .gitlab-ci.yml
build:
image: node:20-alpine
variables:
NODE_OPTIONS: "--openssl-legacy-provider"
script:
- npm ci
- npm run build
Decision Tree: Quick Fix vs. Upgrade
| Situation | Recommended action |
|---|---|
| Need to unblock a legacy project immediately | Add cross-env NODE_OPTIONS=--openssl-legacy-provider to npm scripts |
| Long-lived project, time to invest 1–2 hours | Upgrade Webpack 4 → 5 or react-scripts → v5 |
| CRA project | npm install --save-exact react-scripts@5.0.1 then clean reinstall |
| Angular 11 or 12 project | ng update @angular/cli@13 @angular/core@13 |
| Vue CLI project | Workaround short-term; migrate to Vite long-term |
| Storybook 5–6 | Upgrade to Storybook 7+ (npx storybook@latest upgrade) |
| Custom Webpack 4 config | Follow the Webpack 5 migration guide, ~2–4 hours for an average project |
App code calling createHash('md4') | Replace with 'sha256' or a pure-JS MD4 package |
| Docker/CI only, local machine fine | Pin Node.js version in CI to match local, or add NODE_OPTIONS to CI env |
| Production server (not just build) | Do NOT use --openssl-legacy-provider; upgrade the toolchain |
Safe Patterns After Upgrading to Webpack 5
Verify Webpack 5 hash algorithm (webpack.config.js)
// webpack.config.js — Webpack 5 default is 'xxhash64' on Node 17+
// Both are fully supported without --openssl-legacy-provider
module.exports = {
output: {
// 'xxhash64' is the default and fastest option in Webpack 5
// 'sha256' if you want a well-known cryptographic hash
hashFunction: 'xxhash64',
},
// No special OpenSSL flags needed
};
Using Node.js crypto with supported algorithms (Node.js 17+)
const crypto = require('crypto');
// These algorithms are all supported in OpenSSL 3.0 without the legacy provider:
const sha256 = crypto.createHash('sha256').update('hello').digest('hex');
const sha512 = crypto.createHash('sha512').update('hello').digest('hex');
const sha1 = crypto.createHash('sha1').update('hello').digest('hex');
// List all available algorithms on your Node.js version:
console.log(crypto.getHashes());
// Note: 'md4' will NOT appear in the list on Node.js 17+ without --openssl-legacy-provider
Verify the fix worked — check crypto.getHashes()
// Run this snippet to check if MD4 is available in your environment:
const crypto = require('crypto');
const hashes = crypto.getHashes();
if (hashes.includes('md4')) {
console.log('MD4 is available (Node.js 16 or --openssl-legacy-provider is active)');
} else {
console.log('MD4 is NOT available — Webpack 4 will fail on this Node.js version');
console.log('Use Webpack 5 or set NODE_OPTIONS=--openssl-legacy-provider');
}
Debugging Checklist
- Run
node --version. If it is v17 or higher, OpenSSL 3.0 is the cause. - Check the stack trace for
webpack/lib/util/createHash.js— this confirms Webpack 4 is the caller. - Run
npx webpack --versionor checknode_modules/webpack/package.jsonfor the version. - For CRA, check
node_modules/react-scripts/package.jsonversion — if it is < 5.0.0, upgrade it. - For Angular, run
ng version— if@angular/cliis 11 or 12, upgrade to 13. - Apply the quick fix (
NODE_OPTIONS=--openssl-legacy-provider) to unblock yourself while you plan the proper upgrade. - After upgrading to Webpack 5, run
node -e "require('crypto').createHash('sha256')"to confirm crypto works. - In CI, verify the
node-versioninput in your workflow file matches your local Node.js version, or addNODE_OPTIONSto the CI environment. - Remove all
NODE_OPTIONS=--openssl-legacy-providerreferences from scripts after completing the Webpack 5 upgrade. - If using
node-sass, replace it withsass(Dart Sass) as a separate fix.
Frequently Asked Questions
What is ERR_OSSL_EVP_UNSUPPORTED in Node.js?
ERR_OSSL_EVP_UNSUPPORTED is thrown when Node.js's OpenSSL 3.0 layer rejects a
cryptographic algorithm that was deprecated or removed. The full error is
Error: error:0308010C:digital envelope routines::unsupported.
It almost always fires because Webpack 4 calls crypto.createHash('md4') — an
algorithm OpenSSL 3.0 disabled by default — to generate module IDs and chunk hashes.
Why does ERR_OSSL_EVP_UNSUPPORTED only happen on Node.js 17 and later?
Node.js 17 was the first release to ship with OpenSSL 3.0. Node.js 14 and 16 used OpenSSL 1.1.1, which still supports MD4 by default. When you upgrade from Node.js 16 to any newer version (17, 18, 20, 22), MD4 becomes unavailable without the legacy provider flag, breaking any toolchain that relies on it.
How do I fix ERR_OSSL_EVP_UNSUPPORTED quickly without changing my project?
Set NODE_OPTIONS=--openssl-legacy-provider before running your build or dev server:
- macOS/Linux:
export NODE_OPTIONS=--openssl-legacy-provider && npm start - Windows CMD:
set NODE_OPTIONS=--openssl-legacy-provider && npm start - PowerShell:
$env:NODE_OPTIONS='--openssl-legacy-provider'; npm start - package.json (cross-platform):
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts start"
This is a temporary workaround. Plan an upgrade to Webpack 5 or react-scripts v5 as the permanent fix.
How do I fix ERR_OSSL_EVP_UNSUPPORTED in a Create React App project?
The permanent fix is upgrading react-scripts to v5.0.1+:
npm install --save-exact react-scripts@5.0.1
rm -rf node_modules package-lock.json
npm install
react-scripts@5 bundles Webpack 5, which implements MD4 in pure JavaScript
and never calls OpenSSL for it. If you cannot upgrade yet, use
cross-env NODE_OPTIONS=--openssl-legacy-provider in your npm scripts.
How do I fix ERR_OSSL_EVP_UNSUPPORTED in an Angular CLI project?
Angular CLI 13+ uses Webpack 5 and is not affected. If you are on Angular 11 or 12, upgrade with:
ng update @angular/cli@13 @angular/core@13
If you cannot upgrade immediately, add the workaround to your package.json scripts:
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider ng serve",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider ng build"
How do I fix ERR_OSSL_EVP_UNSUPPORTED in Docker or CI?
In a Dockerfile, add the environment variable before your build step:
ENV NODE_OPTIONS=--openssl-legacy-provider
In GitHub Actions, add it to the env block of your job or step:
env:
NODE_OPTIONS: --openssl-legacy-provider
Long-term, switch your base image to a modern Node.js version and upgrade your build toolchain to Webpack 5, removing the need for the flag entirely.
Is it safe to use --openssl-legacy-provider in production?
Only for build-time tools (Webpack, CRA, Angular CLI) — not for
production Node.js servers. The flag re-enables weak cryptographic algorithms including
MD4. A production server handling HTTP requests or user data should never run with
--openssl-legacy-provider. Use multi-stage Docker builds to ensure the flag
is present only in the build stage and not the runtime stage.
Why does ERR_OSSL_EVP_UNSUPPORTED happen in production or CI but not locally?
Your local machine is likely running Node.js 16 or earlier (OpenSSL 1.1.1), while your
CI pipeline or Docker base image uses Node.js 18, 20, or 22 (OpenSSL 3.0). The fix is to
either align Node.js versions across environments (pin your CI to Node.js 16 temporarily),
add NODE_OPTIONS=--openssl-legacy-provider to CI, or — best — upgrade your
build toolchain to Webpack 5 so it works on all Node.js versions.
Can I downgrade Node.js to fix ERR_OSSL_EVP_UNSUPPORTED?
Yes — downgrading to Node.js 16 (which uses OpenSSL 1.1.1) eliminates the error. Use
nvm to manage versions:
nvm install 16
nvm use 16
node --version # v16.x.x
However, Node.js 16 reached end-of-life in September 2023. Treat downgrading as a last resort and plan the Webpack 5 upgrade instead. Running an EOL Node.js version in production is a security risk.
Related Errors
FATAL ERROR: JavaScript heap out of memory— another build-time fatal error, often from Webpack on large codebases; fix with--max-old-space-sizeERR_DLOPEN_FAILED— native addon ABI mismatch after a Node.js upgrade; similar "upgrade broke my build" patternError: Cannot find module— another common build-time error; missingnpm installor broken node_modulesENOSPC: System limit for number of file watchers reached— another Webpack dev server failure, caused by inotify limits on LinuxERR_REQUIRE_ESM— a different Node.js compatibility break triggered by upgrading packages that dropped CommonJS