npm EACCES: Permission Denied
EACCES means the operating system refused npm access to a specific file or directory. The denied path is the most important clue. A failure under the global npm prefix is a different problem from a root-owned project file, a cache directory, or a container/CI mount. Read the path first, confirm who owns it and which user runs npm, then make the narrowest ownership or installation change that fits that path.
npm ERR! code EACCES or Error: EACCES: permission denied.The message names an operation such as mkdir, open, rename, unlink or access.The failing path points to a global prefix, project directory, npm cache, home directory, or CI/container-mounted path.Do not start with sudo or chmod 777. First collect three facts.
whoami
npm config get prefix
npm root -g
# Then inspect the directory named in the EACCES line:
ls -ld /path/from/the/errorVerify: You can point to the exact denied path, say which user is running npm, and tell whether the path belongs to the global prefix, project, cache or another mounted location.
Why EACCES happens
npm ultimately asks the operating system to create, modify, remove or inspect files. On Unix-like systems, the kernel evaluates the process identity against directory and file permissions. npm reports EACCES when that operation is not permitted. The same code can therefore describe several different ownership mistakes. On Unix-like systems, accessing a path also requires search permission on each directory in the path; the final directory can look writable while an inaccessible parent blocks npm. Inspect the path components as well as the named target. On Linux, namei -l /path/from/the/error displays permissions and ownership along the path; on macOS, inspect each parent directory with ls -ld.
Was npm trying to mkdir, open, rename, unlink or access?
Global prefix, project, cache, home directory, temp directory or mount?
Who owns the parent directory, and which UID/user is npm actually running as?
A useful diagnosis explains all three. If a proposed fix does not explain why that particular user could not write that particular path, it is probably treating the symptom.
Fix #2 — global install prefix is not writable
This is the case covered directly by npm's official EACCES guidance: a global install such as npm install -g package fails because the global installation directory is not writable by the current user. npm recommends reinstalling Node/npm with a Node version manager as the preferred approach, or configuring npm to use a directory owned by your user.
Before changing anything, confirm that the denied path really belongs to the global prefix. A path under /usr/local/lib/node_modules, /usr/lib/node_modules or a similar system location often points here, but use npm config get prefix rather than assuming.
If a version manager is not appropriate, npm documents a user-owned prefix approach on macOS/Linux. Follow the current official instructions because shell startup files and paths differ by environment.
Verify: npm config get prefix points to the intended user-managed location, a normal global install succeeds without privilege escalation, and the installed command is available on PATH.
Fix #3 — the denied path is inside the project
If EACCES names node_modules, a generated file, build directory, lockfile or another path inside your project, changing the global npm prefix will not fix it. Inspect the project directory and its parent ownership. Common causes include a previous command that created files as another user, a container that wrote files with a different UID, an extracted archive with unexpected ownership, or a workspace copied from another environment.
pwd
ls -ld .
ls -ld node_modules 2>/dev/null
ls -l package.json package-lock.json 2>/dev/nullCorrect only the files or project tree that should actually belong to your development user. If the repository is shared, mounted, or managed by deployment tooling, confirm the intended owner first instead of changing it blindly.
Verify: the project files npm needs to modify are writable by the intended development/runtime user, a clean install no longer throws EACCES, and version-control status shows only expected dependency artifacts.
Fix #4 — npm cache or home-directory ownership is wrong
If the denied path is under your npm cache or home directory, inspect that exact directory. The important question is how files there became owned by another user. An old privileged npm run, container, restored backup or changed HOME environment can leave a user cache partially unwritable.
npm config get cache
ls -ld "$(npm config get cache)"
echo "$HOME"Do not automatically delete the entire cache. First determine whether the problem is ownership, disk state, or a different HOME/cache location than expected. If ownership is wrong, repair only the directory that should belong to that user. If a CI job intentionally uses an ephemeral cache, fix the job's user/path policy rather than hand-editing the runner after every build.
Verify: npm reports the expected cache path, the intended process user can write there, and the same install command succeeds without changing unrelated system permissions.
Fix #5 — Docker, CI or bind-mounted workspace
Inside containers and CI, usernames can be misleading because file access is governed by numeric user and group IDs plus mount permissions. A host directory owned by one UID can be mounted into a container whose process runs as another UID. Similarly, one pipeline step may create root-owned artifacts that a later non-root step cannot replace.
id
pwd
ls -ld .
ls -ld /path/from/the/errorFix the ownership contract where it originates: the container user, volume/mount mapping, workspace initialization, or pipeline step. Avoid adding a blanket recursive permission change to every build if the real issue is that one stage writes as the wrong user.
Verify: a fresh runner/container reproduces the corrected UID/GID and mount policy, not just a manually repaired existing workspace.
What not to do
sudo merely because one EACCES error appeared; classify the denied path first.Do not use chmod -R 777 on the project, home directory or system prefix. It removes useful access boundaries without explaining the ownership problem.Do not recursively chown broad system directories such as /usr or /usr/local to your user just to make one global package install.Do not delete package-lock.json for a permission error unless there is a separate lockfile reason.Do not assume every EACCES is a global-install problem. The denied path may be a project file, npm cache, temporary directory or mounted volume.Do not fix a CI/container error only by repairing one running workspace; make the user/mount policy reproducible on a fresh run.Still seeing EACCES?
Capture the first EACCES line from a fresh run and keep the path intact. If a second run fails at a different location, do not combine them into one diagnosis until you know whether the first fix changed the filesystem state.
whoami and, in containers/CI, idnpm config get prefix, npm root -g and npm config get cachels -ld for the denied path and its writable parentwhether the command is local, global, CI, Docker or a bind-mounted workspacethe last command/process that successfully created files in that directoryOfficial references
Still stuck? Ask the community
Share the exact EACCES line, denied path, operating system, Node/npm versions, whether the install is local/global, and the output of the ownership checks above.
Loading community discussion…
Comments could not load here. Open ErrorHarbor Discussions on GitHub →