This error occurs when native Node.js modules are compiled for one Node.js version but run with a different version. The version numbers (e.g., 93 vs 94) represent the NODE_MODULE_VERSION ABI used by different Node.js releases.
The "Module version mismatch" error indicates that a native addon or module (typically written in C/C++) was compiled against a specific version of Node.js's Application Binary Interface (ABI), but is now being loaded by a different version of Node.js with an incompatible ABI. Each Node.js version has an associated MODULE_VERSION number that represents its ABI. For example, Node.js 16.x uses version 93, Node.js 17.x uses version 102, and Node.js 18.x uses version 108. When you see "Expected 93, got 94," it means a native module was compiled for one version but is being used with another. Native modules contain compiled binary code that directly interfaces with Node.js internals. Unlike pure JavaScript modules, they must be recompiled whenever the underlying Node.js version changes significantly. This error most commonly occurs in CI/CD pipelines, Docker containers, or when switching Node.js versions locally without rebuilding dependencies.
First, check which Node.js version you're actually running:
node --versionAlso check which version your package.json or .nvmrc specifies, and ensure they match across all environments (development, CI/CD, production).
The quickest fix is to rebuild all native modules against your current Node.js version:
npm rebuildThis recompiles all native addons in your node_modules folder. For yarn users:
yarn install --forceFor pnpm users:
pnpm rebuildIf rebuilding doesn't work, perform a clean reinstall:
# Remove existing dependencies
rm -rf node_modules
rm -f package-lock.json # or yarn.lock or pnpm-lock.yaml
# Clear npm cache
npm cache clean --force
# Reinstall
npm installOn Windows:
rd /s /q "node_modules"
del package-lock.json
npm cache clean --force
npm installThis ensures all modules, including native addons, are compiled fresh for your current Node.js version.
Ensure consistent Node.js versions everywhere:
Using .nvmrc:
# Create .nvmrc file
echo "18.17.0" > .nvmrc
# Use it with nvm
nvm useIn package.json:
{
"engines": {
"node": ">=18.17.0 <19.0.0"
}
}In Dockerfile:
FROM node:18.17.0-alpineIn CI/CD (GitHub Actions example):
- uses: actions/setup-node@v3
with:
node-version: '18.17.0'Update all environments to use the same Node.js version, then rebuild your dependencies.
Electron requires special handling because it uses a different V8 version than standard Node.js:
# Install electron-rebuild
npm install --save-dev @electron/rebuild
# Rebuild for Electron
npx electron-rebuildOr add it as a postinstall script in package.json:
{
"scripts": {
"postinstall": "electron-rebuild"
}
}This recompiles native modules specifically for Electron's Node.js environment.
Some packages (like sharp, canvas, or sqlite3) provide pre-built binaries. Ensure you're downloading the correct ones:
# Force download of pre-built binaries
npm install --force
# Or for specific packages
npm rebuild sharp --verboseIf pre-built binaries aren't available for your Node.js version, the package will compile from source, which requires build tools (python, make, g++/clang) to be installed.
MODULE_VERSION reference table:
| Node.js Version | MODULE_VERSION |
|-----------------|----------------|
| 14.x | 83 |
| 15.x | 88 |
| 16.x | 93 |
| 17.x | 102 |
| 18.x | 108 |
| 19.x | 111 |
| 20.x | 115 |
| 21.x | 120 |
Build requirements for native modules:
To compile native modules from source, you need platform-specific build tools:
- Linux: build-essential, python3
- macOS: Xcode Command Line Tools (xcode-select --install)
- Windows: Visual Studio Build Tools or windows-build-tools npm package
Docker considerations:
When using Docker, the Node.js version in your Dockerfile must match your development environment. Use multi-stage builds to ensure consistency:
FROM node:18.17.0-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
FROM node:18.17.0-alpine
WORKDIR /app
COPY --from=builder /app .
CMD ["node", "index.js"]CI/CD caching gotchas:
Many CI systems cache node_modules to speed up builds. If you change Node.js versions, you must invalidate this cache:
# GitHub Actions example
- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}-${{ matrix.node-version }}Note the matrix.node-version in the cache key—this ensures separate caches per Node.js version.
Debugging which module is causing the error:
If the error message doesn't specify which module is problematic, enable verbose logging:
NODE_DEBUG=module node index.jsOr check the stack trace carefully—the first native module in the trace is likely the culprit.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams