npm EACCES Permission Denied in CI - Fix File and Cache Permissions
EACCES means npm tried to write to a path it does not own. In CI this is usually a cache directory or a global install location with mismatched ownership, often from running as a different user inside a container.
What this error means
npm install fails with code EACCES and a permission denied syscall on a path under ~/.npm, /usr/lib/node_modules, or the project directory. It frequently appears when the job switches users between steps or mounts a volume owned by root.
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/lib/node_modules/foo
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/foo'Common causes
The npm cache or install dir is owned by another user
A cache populated as root cannot be written by a non-root job step, producing permission-denied errors mid-install.
Global install into a system path without rights
Installing a package globally writes to /usr/lib or /usr/local, which the CI user often cannot modify.
How to fix it
Fix ownership of the cache and project
- Chown the npm cache and working directory to the running user.
- Re-run the install.
sudo chown -R "$(id -u):$(id -g)" ~/.npm "$PWD"
npm ciAvoid global installs that need root
- Install tools as devDependencies and call them via npx or package scripts.
- Or set a user-writable npm prefix instead of a system path.
npm config set prefix "$HOME/.npm-global"How to prevent it
- Run all npm steps as a consistent user, keep the cache in a user-owned path, and prefer local devDependencies over global installs so no step needs elevated permissions.