Skip to content
Latchkey

npm EACCES "permission denied" on the npm cache - Fix in CI

EACCES on the npm cache or node_modules means the user running npm cannot write where it needs to. In CI and Docker this is almost always a directory owned by root from an earlier step.

What this error means

npm fails while writing to ~/.npm/_cacache or node_modules with "EACCES: permission denied". It frequently appears after a step ran as root (or a cached layer was created as root) and a later step runs as a non-root user.

npm output
npm error code EACCES
npm error syscall mkdir
npm error path /home/runner/.npm/_cacache/...
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/home/runner/.npm/_cacache/...'

Common causes

Cache or node_modules owned by root

A previous step (often a Docker build run as root, or a sudo npm call) created ~/.npm or node_modules owned by root. When the build user runs npm next, it cannot write there.

Installing globally without permission

npm install -g writes to a system prefix the CI user cannot modify. Global installs as non-root commonly hit EACCES.

How to fix it

Fix ownership of the cache and modules

Hand the npm directories back to the current user.

Terminal
sudo chown -R "$(id -u):$(id -g)" "$HOME/.npm" node_modules 2>/dev/null || true
npm ci

Avoid root-owned state and sudo installs

  1. Do not run sudo npm install - it leaves root-owned files behind.
  2. Use a user-writable global prefix (npm config set prefix ~/.npm-global) or npx instead of global installs.
  3. In Dockerfiles, run npm as the same user that runs the build, not root.

How to prevent it

  • Never mix root and non-root npm runs in the same workspace.
  • Set a user-writable npm prefix for global tools.
  • Bake correct ownership into base images.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →