/개발/Node.js error:0308010C digital envelope unsupported — a fix runbook
DevelopmentNode.jsERR_OSSL_EVP_UNSUPPORTED

Node.js error:0308010C digital envelope unsupported — a fix runbook

Did a Node 17/18/20 upgrade break your webpack build with error:0308010C digital envelope routines unsupported and ERR_OSSL_EVP_UNSUPPORTED? This copy-paste runbook covers a 30-second diagnostic table, the --openssl-legacy-provider workarou

Node.js error:0308010C digital envelope unsupported — a fix runbook

The build that worked yesterday broke after you only upgraded Node

You didn't touch a single line of code, but the build suddenly exploded. Nine times out of ten, the raw error looks like this. First, confirm one of these three siblings in the logs.

TEXT
Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:71:19)
    ...
  opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'

The trigger is almost always one thing: you upgraded Node locally with nvm, the CI runner's default Node image moved up (e.g. actions/setup-node default, the node:lts Docker tag), or a teammate changed .nvmrc. In other words, the runtime environment changed, not the code.

Scope: Node.js 17+ (17/18/20/22), webpack 4-based build pipelines — react-scripts (CRA) 4.x, @vue/cli-service 4.x, older gatsby, old storybook, and similar. It happens the same way on every OS that ships OpenSSL 3.0 (Windows/macOS/Linux).

This is not a conceptual lecture — it's a copy-paste runbook. Pin the cause with the 30-second diagnostic table, then apply the 5-minute workaround (Path A) or the root-cause fix (Path B) immediately.

30-second diagnostic table: error string → cause → immediate action

Find the string from your logs in the left column and jump straight to the action on the right.

Error stringNode versionLikely causeImmediate action (Path A/B)
error:0308010C:digital envelope routines::unsupported17+ (default switched at 17)OpenSSL 3.0 disables legacy hashes (MD4, etc.) by default → webpack 4 chunk hash calculation failsA: NODE_OPTIONS=--openssl-legacy-provider / B: Upgrade webpack 5 and the build tool
ERR_OSSL_EVP_UNSUPPORTED17+Same cause, in Node error-code formA same / B same
digital envelope routines::initialization error (03000086)17+Same cause; nested error that also appears in opensslErrorStackA same / B same

The key breakpoint is Node 17. Through Node 16, OpenSSL 1.1.1 was bundled; from Node 17 onward, OpenSSL 3.0 became the default, and 18/20/22 LTS inherited that. OpenSSL 3.0 turns off old legacy-provider algorithms by default for security, so older webpack that used them internally throws the error above.

The cause in one line: OpenSSL 3.0 disables legacy hash algorithms such as MD4 by default → webpack 4's chunk hash (filename hash) calculation fails. You don't need more background than that to fix it.

ESM/CommonJS errors (Cannot use import statement outside a module, require is not defined) have a completely different cause. If that's you, see the 'Cannot use import statement outside a module' fix runbook — this post covers only the OpenSSL hash family.

Path A — temporary workaround (5-minute cut)

Use this when you need the build to run right now. The --openssl-legacy-provider flag turns OpenSSL's legacy provider back on.

Method 1) Inject the flag directly into package.json scripts

For react-scripts you can pass it as a CLI argument.

JSON
{
  "scripts": {
    "start": "react-scripts --openssl-legacy-provider start",
    "build": "react-scripts --openssl-legacy-provider build"
  }
}

For Vue CLI, put it in front of the service command.

JSON
{
  "scripts": {
    "serve": "vue-cli-service --openssl-legacy-provider serve",
    "build": "vue-cli-service --openssl-legacy-provider build"
  }
}

If the CLI doesn't accept the flag, or you want one approach that works on every OS, cross-env + NODE_OPTIONS is the safest.

Bash
npm i -D cross-env
JSON
{
  "scripts": {
    "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts start",
    "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts build"
  }
}

With cross-env you don't have to care about Windows set vs Unix export. For team projects, this is the recommended approach.

Method 3) Temporary env var in the shell (one-off run)

macOS / Linux (bash·zsh)

Bash
export NODE_OPTIONS=--openssl-legacy-provider
npm run build

Windows CMD

CMD
set NODE_OPTIONS=--openssl-legacy-provider
npm run build

Windows PowerShell

POWERSHELL
$env:NODE_OPTIONS = "--openssl-legacy-provider"
npm run build

Expected success: The build that previously died immediately on ERR_OSSL_EVP_UNSUPPORTED proceeds through compilation and you get Compiled successfully or a bundle artifact.

If it doesn't match expectations:

  • Still the same error → Check with node -v that the Node actually running is 17+. The shell session may have been replaced so the env var never took effect.
  • --openssl-legacy-provider is not allowed in NODE_OPTIONS → In some Node 22+ situations the flag can be rejected. In that case Path B (upgrade) is effectively mandatory.
  • If the error string changed to something ERR_REQUIRE_ESM/import-related, the OpenSSL problem is solved and you have a separate ESM issue.

Method 4) Dockerfile ENV

For container builds, bake it in at the image level (methods 4–5 only on temporary images — see the caveats later).

Dockerfile
FROM node:20-alpine
WORKDIR /app
ENV NODE_OPTIONS=--openssl-legacy-provider
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

Method 5) GitHub Actions env block

If it broke in CI, inject the env var into the workflow. Both step level (recommended) and job level work.

YAML
name: build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    # job 레벨: 이 job의 모든 step에 적용
    env:
      NODE_OPTIONS: --openssl-legacy-provider
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      # step 레벨: 이 step에만 국한하고 싶을 때
      - run: npm run build
        env:
          NODE_OPTIONS: --openssl-legacy-provider

If you don't pin setup-node's node-version, it will break again when the runner default moves up. Pinning tips — including cache and matrix builds — are in Setting Node build env vars in GitHub Actions.

Path B — root-cause fix: build without the legacy provider

A workaround "revives algorithms that were turned off for security," so it cannot be a permanent fix. Move to the below this sprint.

Step 1 — Check the current webpack version

Bash
npm ls webpack

Expected result (this is the thing to fix): If you see webpack@4.x.x, that is the root cause of this error.

TEXT
project@1.0.0
└─┬ react-scripts@4.0.3
  └── webpack@4.44.2

If webpack@5.x is already showing but you still get the error, webpack 4 may be nested in the dependency tree — check the full tree with npm ls webpack --all.

Step 2 — Build-tool upgrade mapping

webpack 5 usually comes along automatically when you upgrade the build tool. Raising the parent tool is safer than bumping webpack alone.

Build toolwebpack 5 support startsAction command
react-scripts (CRA)From 5.0.0npm i react-scripts@5
@vue/cli-serviceFrom 5.0.0npm i -D @vue/cli-service@^5
gatsbyLatest majornpm i gatsby@latest
Pure webpack project5.xnpm i -D webpack@5 webpack-cli@latest
Bash
# CRA 예시
npm i react-scripts@5
npm dedupe

Step 3 — Remove the workaround and verify

After the upgrade, remove every flag and env var you added in Path A and confirm the build passes in a clean state.

Bash
# 1) package.json에서 --openssl-legacy-provider / NODE_OPTIONS 제거
# 2) 캐시·모듈 초기화
rm -rf node_modules package-lock.json
npm install
# 3) 환경변수 없는 상태에서 빌드
unset NODE_OPTIONS   # Windows PowerShell: Remove-Item Env:\NODE_OPTIONS
npm run build

Expected success: Compiled successfully without NODE_OPTIONS. You no longer depend on the legacy provider.

If it doesn't match expectations:

  • Still ERR_OSSL_EVP_UNSUPPORTED → Recheck with npm ls webpack --all whether webpack 4 is still present. A third-party plugin may be pulling it in.
  • The error changed to a different build error (e.g. missing polyfills for Buffer/process) → That's a normal webpack 5 breaking change. Handle it individually with resolve.fallback or node-polyfill-webpack-plugin. The OpenSSL issue is already solved.

Stick with CRA, or move to Vite?

react-scripts (CRA) is effectively stalled on maintenance, so migrating to Vite has become the default for new projects. If a webpack 4→5 migration is expensive, it's worth weighing a move to Vite with the same effort. Vite is esbuild/Rollup-based, so this OpenSSL issue never happens.

Conclusion + troubleshooting checklist

workaround now, root-cause fix this sprint. Walk through in this order.

  • Confirm 0308010C / ERR_OSSL_EVP_UNSUPPORTED / initialization error in the logs
  • Confirm 17+ with node -v (pin the cause)
  • If you're in a hurry: work around with cross-env NODE_OPTIONS=--openssl-legacy-provider
  • Do not permanently freeze the workaround flag into CI — mark it as temporary in the commit message and PR
  • Confirm webpack 4 with npm ls webpack
  • Upgrade with react-scripts@5 / @vue/cli-service@5 / gatsby@latest
  • Remove the workaround and verify the build passes without NODE_OPTIONS
  • Pin the Node version in .nvmrc, setup-node, and the Docker tag to prevent recurrence

Caution: --openssl-legacy-provider revives algorithms that OpenSSL 3.0 disabled for security. It is only a temporary measure for developer convenience — do not leave it permanently in a production CI pipeline. Use it on the premise that you will strip it out after the root-cause fix (webpack 5).

The key to preventing recurrence is pinning the Node version. Locally use .nvmrc/Volta; in CI, set setup-node's node-version explicitly so a runner default change doesn't shake you — concrete steps are in the Node version management (nvm/Volta) guide.

References: official docs

The primary sources for the behavior, settings, and errors in this post are the official docs below. Check version-specific options and exact behavior there.

FAQ

Q. Can I just leave --openssl-legacy-provider in CI forever? A. Not recommended. It revives legacy algorithms that were disabled for security, so it is a temporary workaround. The proper path is to upgrade to webpack 5 so the build works without the flag, then remove it.

Q. I upgraded to Node 20/22 LTS and the flag doesn't take effect or is rejected. A. On recent Node, the legacy-provider flag in NODE_OPTIONS can be restricted. In that case the workaround is unavailable, so Path B (webpack 5 / build-tool upgrade) is effectively mandatory. If the migration cost is high, also consider moving to Vite.

Q. I upgraded webpack to 5 and still get the same error. A. Check the dependency tree with npm ls webpack --all. If a third-party plugin or nested dependency still pulls in webpack 4, the error continues. Upgrade that package to a current version, or clean up duplicates with npm dedupe.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.