How to fix npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib/node_modules' in npm
npm tried to change ownership of a file or directory but the OS/FS blocks lchown (common on Windows/WSL and non-root global prefixes). Use user-owned prefixes and avoid chown on unsupported filesystems.
Quick fix
Fixes npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib/node_modules'
npm config get prefix
stat -f -c %T $(npm config get prefix) 2>/dev/null || stat -f $(npm config get prefix)- Check prefix and filesystem support
- Use user-owned prefix instead of chown
- Avoid chown on Windows/WSL; reinstall locally
- Clean and retry
npm config get prefixstat -f -c %T $(npm config get prefix) 2>/dev/null || stat -f $(npm config get prefix)npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib/node_modules'
What this error means
npm occasionally calls lchown when installing globally or adjusting permissions in node_modules. On Windows/WSL and many container mounts, lchown is either unsupported or restricted, so the syscall returns EPERM and the install stops. This happens when installing globally as a non-root user, when the prefix is root-owned, inside Docker/CI with mismatched users, or on NTFS/SMB where chown semantics are limited. The fix is usually to avoid needing chown by keeping npm files in user-owned locations.
Typical symptoms
- npm install -g fails with EPERM: lchown on /usr/local/lib/node_modules
- Works with sudo/Admin but fails as normal user
- WSL/Windows emits "operation not permitted" even with correct mode bits
- Docker/CI jobs fail when running npm as non-root against root-owned prefixes
- Staging directories remain after failure
Common causes
- Global prefix owned by root/system; npm attempts ownership adjustments
- Filesystem does not support chown (NTFS/SMB, some container volumes)
- Docker/CI running as non-owner of the mounted prefix
- Corporate policies blocking chown on /usr/local or /opt/homebrew
- Mixing sudo and user installs leaving root-owned artifacts
How to fix "npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib/node_modules'"
npm config get prefix
stat -f -c %T $(npm config get prefix) 2>/dev/null || stat -f $(npm config get prefix)mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
npm config set cache ~/.npm-cache
export PATH="$HOME/.npm-global/bin:$PATH"On NTFS/SMB mounts, chown is ignored or blocked. Install on a Linux/ext4 path (WSL ~/projects) or run without forcing ownership changes.
sudo rm -rf $(npm config get prefix)/lib/node_modules/.staging 2>/dev/null || true
npm cache clean --force
npm install -g <package>Run containers with matching UID/GID or chown the workspace/prefix once at startup so npm never needs to call lchown.
Advanced notes
Homebrew installs under /opt/homebrew on macOS can drift to root-owned; prefer nvm/fnm to keep globals in $HOME and avoid chown. In CI, ensure the workspace is owned by the job user before npm ci; copying caches from root-owned layers often triggers lchown failures. On Windows/WSL, chown is largely a no-op—using per-user prefixes and avoiding sudo eliminates the syscall entirely.
Frequently asked questions
- What does "npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib" mean?
- npm occasionally calls lchown when installing globally or adjusting permissions in node_modules. On Windows/WSL and many container mounts, lchown is either unsupported or restricted, so the syscall returns EPERM and the install stops. This happens when installing globally as a non-root user, when the prefix is root-owned, inside Docker/CI with mismatched users, or on NTFS/SMB where chown semantics are limited.
- How do I fix "npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib"?
- npm tried to change ownership of a file or directory but the OS/FS blocks lchown (common on Windows/WSL and non-root global prefixes). Use user-owned prefixes and avoid chown on unsupported filesystems.
- What causes "npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib"?
- Global prefix owned by root/system; npm attempts ownership adjustments Filesystem does not support chown (NTFS/SMB, some container volumes) Docker/CI running as non-owner of the mounted prefix
- Is the "npm ERR! Error: EPERM: operation not permitted, lchown '/usr/local/lib" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚npm Official Documentation
- 📖npm Docs: Permissions guidance(Official Docs)
- 📖Microsoft Docs: WSL file permission considerations(Official Docs)
- 💬Stack Overflow: EPERM lchown during npm install(Stack Overflow)
- 🐙