This error occurs when npm scripts fail because the shell executable (sh, bash, or cmd) cannot be found in PATH. It is most common on Windows systems where shell configuration or PATH settings are incorrect.
The "spawn sh ENOENT" error occurs when npm attempts to execute a script using the shell (`sh`) but cannot locate the shell executable. ENOENT stands for "Error NO ENTry" (or "No such file or directory"), indicating that the operating system cannot find the specified program. When you run an npm script, npm uses Node.js's child_process module to spawn a shell that executes your script commands. By default, npm uses `sh` on Unix-like systems and `cmd.exe` on Windows. If the shell binary is missing from the system PATH or npm's shell configuration points to a non-existent location, this error occurs. This error is overwhelmingly more common on Windows systems because Windows doesn't have a native `sh` shell. It can occur when Git Bash or WSL is partially installed, when npm's script-shell configuration is incorrectly set, or when the system PATH is corrupted. On macOS and Linux, this error is rare and usually indicates a severely misconfigured system or a minimal Docker container lacking shell binaries.
The most common fix on Windows is to reset or delete the npm script-shell configuration:
# Check current script-shell setting
npm config get script-shell
# Delete custom script-shell (restores default behavior)
npm config delete script-shell
# Verify it's removed
npm config get script-shell
# Should show "undefined" or the default valueIf npm was previously configured to use a shell that no longer exists (like a removed Git Bash installation), this will fix the issue.
Alternatively, explicitly set it to use cmd on Windows:
npm config set script-shell "C:\\Windows\\System32\\cmd.exe"On Windows, the cmd.exe shell lives in System32. Ensure this directory is in your PATH:
1. Open Start Menu and search for "Environment Variables"
2. Click "Edit the system environment variables"
3. Click "Environment Variables" button
4. Under "System variables", find and select "Path", then click "Edit"
5. Verify these entries exist (add if missing):
- C:\Windows\System32
- C:\Windows
You can also check and fix PATH from PowerShell:
# Check if System32 is in PATH
$env:Path -split ';' | Where-Object { $_ -like '*System32*' }
# Add System32 to PATH for current session
$env:Path = "C:\Windows\System32;$env:Path"
# Test if cmd works
cmd /c echo "PATH is working"After modifying environment variables, restart your terminal or IDE.
If you have Git for Windows installed, you can configure npm to use Git Bash's shell:
# Set Git Bash as the script shell
npm config set script-shell "C:\\Program Files\\Git\\bin\\bash.exe"
# Or if Git is installed in a different location, find it first:
where gitCommon Git Bash shell locations:
- C:\Program Files\Git\bin\bash.exe
- C:\Program Files (x86)\Git\bin\bash.exe
- C:\Users\YourUsername\AppData\Local\Programs\Git\bin\bash.exe
Verify the path exists before setting it:
Test-Path "C:\Program Files\Git\bin\bash.exe"In Docker containers, especially those based on minimal images like Alpine or distroless, the shell may be missing:
For Alpine-based images:
FROM node:20-alpine
# Alpine uses ash, not bash - but /bin/sh is typically available
# If you need bash specifically:
RUN apk add --no-cache bash
# Ensure shell is available
RUN which sh && which bashFor distroless or minimal images:
# Use a multi-stage build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM gcr.io/distroless/nodejs20
COPY --from=builder /app/node_modules ./node_modules
COPY . .
CMD ["index.js"]Or install shell in minimal images:
FROM debian:slim
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm \
&& rm -rf /var/lib/apt/lists/*If you're maintaining a package that spawns processes, use the shell: true option to let Node.js handle shell resolution:
const { spawn } = require('child_process');
// Instead of spawning directly:
// spawn('sh', ['-c', 'echo hello']);
// Use shell: true option:
spawn('echo', ['hello'], {
shell: true, // Node.js will use appropriate shell for platform
stdio: 'inherit'
});Or use the cross-spawn package for better cross-platform support:
npm install cross-spawnconst spawn = require('cross-spawn');
// cross-spawn handles Windows shell issues automatically
const result = spawn.sync('npm', ['run', 'build'], {
stdio: 'inherit'
});This approach works across Windows, macOS, and Linux without requiring specific shell configurations.
Environment variables can override shell settings. Check for conflicts:
Windows PowerShell:
# Check shell-related environment variables
$env:SHELL
$env:ComSpec
$env:COMSPEC
# ComSpec should point to cmd.exe
# If it's wrong, fix it:
$env:ComSpec = "C:\Windows\System32\cmd.exe"
# Or set it permanently via System Properties
[Environment]::SetEnvironmentVariable("ComSpec", "C:\Windows\System32\cmd.exe", "Machine")Linux/macOS:
# Check SHELL variable
echo $SHELL
# Should show /bin/bash, /bin/zsh, or similar
# If empty or wrong, set it:
export SHELL=/bin/bashIn npm scripts or .npmrc:
# .npmrc file
script-shell=/bin/bashIf other fixes don't work, a clean reinstall may be necessary:
Windows:
1. Uninstall Node.js from Control Panel
2. Delete remaining folders:
- C:\Users\YourName\AppData\Roaming\npm
- C:\Users\YourName\AppData\Roaming\npm-cache
- C:\Users\YourName\.npmrc
3. Download and install latest Node.js from nodejs.org
4. Open new terminal and verify:
node --version
npm --version
npm config listmacOS/Linux:
# Using nvm (recommended)
nvm uninstall current
nvm install --lts
nvm use --lts
# Clear npm cache
npm cache clean --force
# Verify shell configuration
npm config get script-shellReset all npm config:
npm config edit # Opens config file - delete problematic entries
# Or delete the entire config file
rm ~/.npmrc### Understanding npm Shell Selection
npm selects the shell for running scripts based on:
1. npm config script-shell: Checked first, overrides all defaults
2. SHELL environment variable: Used on Unix-like systems if script-shell not set
3. ComSpec environment variable: Used on Windows if script-shell not set
4. Platform defaults: /bin/sh on Unix, cmd.exe on Windows
Check what npm will use:
npm config get script-shell
echo $SHELL # Unix
echo %ComSpec% # Windows cmd
$env:ComSpec # Windows PowerShell### WSL Complexity
Windows Subsystem for Linux adds complexity because both Windows and Linux shells coexist:
- Running npm from Windows PowerShell/CMD uses Windows shell resolution
- Running npm from WSL terminal uses Linux shell resolution
- PATH variables are different in each environment
Common issues:
# In WSL, check you're using Linux npm, not Windows npm
which npm
# Should show /usr/bin/npm, not /mnt/c/...
# If Windows npm is being used from WSL, it looks for Windows paths
# Fix: Use WSL npm or configure Windows npm properly### npm-run-all and Concurrent Scripts
Packages like npm-run-all or concurrently spawn multiple npm scripts and can encounter this error:
{
"scripts": {
"start": "npm-run-all --parallel server client"
}
}If spawn sh ENOENT occurs here:
1. Fix the underlying shell configuration (steps 1-3)
2. Or configure the package to use a specific shell:
// For concurrently, use --shell flag
// package.json
{
"scripts": {
"start": "concurrently --raw \"npm run server\" \"npm run client\""
}
}### CI/CD Pipeline Considerations
Different CI environments have different shell defaults:
GitHub Actions:
- name: Install dependencies
shell: bash # Explicitly set shell
run: npm ciGitLab CI:
before_script:
- which sh bash # Verify shells exist
- npm config set script-shell /bin/bashJenkins:
sh '''
npm config set script-shell /bin/bash
npm install
'''### Checking for Antivirus Interference
Some antivirus software blocks shell access. To diagnose:
1. Temporarily disable real-time protection
2. Run the npm command
3. If it works, add exceptions for:
- C:\Windows\System32\cmd.exe
- C:\Program Files\Git\bin\bash.exe
- Your project directory
### Minimal Docker Images
When using minimal Docker images, you may need to explicitly install a shell:
# For busybox-based images
FROM busybox
# busybox includes /bin/sh
# For scratch (empty) images - must use multi-stage
FROM node:20 AS builder
# ... build steps
FROM scratch
COPY --from=builder /bin/sh /bin/sh
COPY --from=builder /lib/* /lib/
# This is complex - prefer distroless or slim images insteadBetter approach: Use appropriately sized base images:
- node:20-slim - Debian-based, minimal but has bash
- node:20-alpine - Alpine-based, has ash (sh-compatible)
- gcr.io/distroless/nodejs20 - No shell, run Node directly
npm ERR! code ENOAUDIT npm ERR! Audit endpoint not supported
How to fix "npm ERR! code ENOAUDIT - Audit endpoint not supported"
npm ERR! code EBADDEVENGINES npm ERR! devEngines.runtime incompatible with current node version
How to fix "npm ERR! code EBADDEVENGINES - devEngines.runtime incompatible with current node version"
npm ERR! code ETOOMANYARGS npm ERR! Too many arguments
How to fix "npm ERR! code ETOOMANYARGS - Too many arguments"
npm ERR! code EINVALIDTAGNAME npm ERR! Invalid tag name: tag names cannot contain spaces
How to fix "npm ERR! code EINVALIDTAGNAME - tag names cannot contain spaces"
npm ERR! code E400 npm ERR! 400 Bad Request
How to fix "npm ERR! code E400 - 400 Bad Request" error