ERR_OSSL_EVP_UNSUPPORTED / error:0308010C — Find the Crypto Consumer
ERR_OSSL_EVP_UNSUPPORTED means a crypto operation requested through Node.js is not supported by the active OpenSSL configuration. The well-known error:0308010C:digital envelope routines::unsupported fingerprint became common around the Node/OpenSSL 3 transition, but the useful question is not “which flag hides it?” It is which dependency, build tool or application code requested the unsupported crypto behavior?
ERR_OSSL_EVP_UNSUPPORTED.The stack may include error:0308010C:digital envelope routines::unsupported, createHash, crypto, webpack or another build/runtime dependency.The failure appeared after changing Node/runtime/container/CI environment, or an older dependency now runs against a newer crypto policy.node -p "process.version"
node -p "process.versions.openssl"
node -p "process.execArgv"Then rerun the exact failing command and read the first meaningful project/tool frame above Node internals. Preserve the full error code and stack. A Node/OpenSSL version pair tells you the boundary; the stack tells you who is asking for the crypto operation.
Guardrail: Never turn --openssl-legacy-provider into the permanent fix before identifying what actually requires legacy crypto behavior.
Verify: You know the Node version, OpenSSL version, exact failing command and likely crypto consumer.
Diagnostic flow — boundary → owner → supported remediation
What Node and OpenSSL versions run the failing command?
Which stack frame/dependency/application code requests the operation?
Is it your code, a direct dependency, framework/build tool or transitive package?
Upgrade/migrate the owner or crypto behavior using supported versions.
Run without legacy-provider compatibility and verify the exact original workflow.
Fix #2 — confirm whether the runtime boundary changed
Node 17 introduced OpenSSL 3.0 and documented tighter restrictions on allowed algorithms/key sizes; Node exposed --openssl-legacy-provider as a temporary workaround for applications affected by those restrictions. Do not assume every current occurrence is “a Node 17 bug”: modern projects may hit the same error family when old crypto assumptions meet a newer Node/OpenSSL policy.
Compare the failing environment with the last known working one: local vs CI, Docker base image, build image, deployment runtime and version-manager selection. Check what actually runs rather than what package.json merely declares. A lockfile can be identical while the Node/OpenSSL runtime changes underneath it. process.execPath identifies the executable running that diagnostic process; for npm scripts, also print the same values inside the failing script/job because shell PATH/version-manager behavior can differ from your interactive terminal.
For containers and CI, record the image tag/digest and run the version check inside the failing job/container. A developer shell's node -v does not prove what a Docker build stage, CI runner or deployment image executes.
node -p "process.version + ' / OpenSSL ' + process.versions.openssl"
which node
node -p "process.execPath"Verify: You can explain whether the failure correlates with a runtime/environment change and which Node binary executes the failing workflow.
Fix #3 — if build tooling owns it, repair the toolchain
If the first useful stack frames point into webpack, a framework CLI, loader/plugin or another dependency, identify the owning package and its installed version. Do not upgrade every package blindly. Trace the direct/transitive relationship, then check the framework/tool's supported Node matrix and release path.
npm ls webpack
npm explain webpack
npm ls <package-from-stack>output.hashFunction with md4 behavior, and webpack 5.54+ added xxhash64 support. That explains many famous Node/OpenSSL 3 build failures, but ERR_OSSL_EVP_UNSUPPORTED itself only tells you that an EVP/crypto operation is unsupported under the active provider/policy. Confirm the stack owner before applying webpack-specific advice.If webpack is actually the owner, prefer the framework/webpack upgrade path supported by that project. Webpack's current documentation still documents output.hashFunction with md4 as the baseline option and notes xxhash64 support from webpack 5.54+, so the exact framework/configuration still matters. Avoid cargo-cult edits such as forcing a hash function in generated configuration that the framework owns or will overwrite.
Verify: After a supported dependency/framework upgrade, rerun the exact build under the intended Node version without legacy-provider compatibility.
Fix #4 — if your application owns the crypto call, migrate the crypto behavior
If the stack reaches your own crypto.createHash(), signing, encryption or key-loading code, inspect the exact algorithm, key format/size and operation being requested. Do not replace an algorithm merely because another name “works”; crypto choices are protocol/security decisions and may need compatibility with stored data or external systems.
Use Node's supported crypto APIs and the algorithm/protocol requirements appropriate to your application. If this protects real credentials, signatures or encrypted data, treat migration as a security/protocol change—not a syntax fix. Identify whether the algorithm is used for non-security build hashing, password hashing, signatures, encryption, key derivation or an external protocol. Those use cases are not interchangeable.
Verify: The same application test succeeds on the intended Node/OpenSSL runtime using the supported crypto design, and any required interoperability/security tests still pass.
Fix #5 — use legacy provider only as a diagnostic/temporary bridge
Node provides the --openssl-legacy-provider option to enable OpenSSL 3's legacy provider. Node introduced it specifically as a temporary workaround for tightened OpenSSL 3 restrictions. If enabling it makes the exact failing workflow succeed, that is strong evidence that legacy crypto behavior is involved—but it still does not tell you which package owns the request.
node --openssl-legacy-provider your-script.jsFor npm scripts, environment-specific ways of setting NODE_OPTIONS differ across shells and CI systems. Node processes NODE_OPTIONS before command-line options; command-line singleton options can override the corresponding environment option. That makes a hidden NODE_OPTIONS in a CI secret/variable, Docker ENV, shell profile or process manager easy to miss while comparing environments.
node -p "process.env.NODE_OPTIONS || '(unset)'"
node -p "process.execArgv"Important: process.execArgv shows Node-specific options passed explicitly for the current process; inspect process.env.NODE_OPTIONS separately when hunting inherited compatibility flags. Prefer an explicit, short-lived diagnostic run and document why it exists. Avoid silently baking the legacy-provider flag into global shell profiles, base images, organization-wide CI variables or production process-manager configuration.
Verify: The bridge changes the failure as expected, you have identified the owner, and the final supported remediation works after the bridge is removed.
Fix #6 — make sure this is actually the same OpenSSL problem
ERR_OSSL_EVP_UNSUPPORTED is specific enough to investigate EVP/crypto support, but “OpenSSL error” is not. Certificate verification failures, TLS protocol negotiation, native-addon ABI problems and missing shared libraries have different evidence and fixes. Preserve the complete Node error code and top stack frames before applying this guide.
Verify: The final diagnosis explains the original error code and stack—not merely that a compatibility flag made one command proceed.
What not to do
--openssl-legacy-provider a permanent global default before identifying the crypto consumer.Do not pin an obsolete/EOL Node release indefinitely just because it predates the OpenSSL policy change; use a supported LTS release compatible with the application/toolchain.Do not hide --openssl-legacy-provider in global NODE_OPTIONS, CI organization variables, Docker base images or production process-manager config.Do not upgrade or downgrade the entire dependency tree blindly; trace the package/application frame that owns the crypto call.Do not replace application cryptography with an arbitrary algorithm solely to clear the exception.Do not assume every error:0308010C stack is webpack without checking the actual stack and dependency tree.Do not confuse npm ERESOLVE dependency-resolution failures with this runtime crypto compatibility failure.Still seeing ERR_OSSL_EVP_UNSUPPORTED?
Escalate with the runtime boundary and ownership evidence. “It works with legacy provider” is useful evidence, but it is not a root-cause report.
process.versions.openssl values from the failing environmentexact failing command and whether local/CI/container environments differpackage/version owning the first non-Node crypto framerelevant npm ls/npm explain relationshipwhether legacy provider changes the result, used only as diagnostic evidencelast known working runtime/toolchain combination if knowneffective NODE_OPTIONS and whether the flag comes from shell, CI, container or process-manager configurationcontainer image tag/digest or CI runtime identity when the failing environment is not localOfficial references
Still stuck? Ask the community
Share the Node/OpenSSL versions, exact command, package/tool frame and a redacted stack trace.
Loading community discussion…
Comments could not load here. Open ErrorHarbor Discussions on GitHub →