npm EACCES without sudo: fix the cache and global prefix
Reproduced on npm 11.19.0: how to tell the cache EACCES from the global-install EACCES by the path line, and the two fixes npm documents that end sudo for good.
TL;DR#
EACCES from npm means the operating system refused a write because the folder belongs to another user, almost always root. There are two different folders behind it, and the path line of the error tells you which one:
- Your cache,
~/.npm. A previoussudo npm …left root-owned files there. Give the folder back to yourself once, with thechowncommand npm prints, and stop using sudo. - The global folder,
/usr/local/lib/node_modules. Node.js was installed system-wide, sonpm install -gwrites into a root-owned prefix. Install Node.js with a version manager such as nvm (npm's recommended fix), or set the npm prefix to a folder in your home directory and add itsbintoPATH.
Both cases were reproduced on 11 October 2026 in the official node:24 Docker image (Node.js 24.21.0, npm 11.19.0) as the image's non-root user.
The error#
The Stack Overflow question dates from npm 1.2.18 on macOS (System Darwin 12.2.0). Every npm search or npm install failed unless it was run with sudo:
npm ERR! Error: EACCES, open '/Users/chietala/.npm/-/all/.cache.json'
npm ERR! Please try running this command again as root/Administrator.
npm ERR! code EACCESCurrent npm still fails on the same causes, but it now prints a diagnosis. When the failing path is inside the cache, npm 11.19.0 prints this:
npm error code EACCES
npm error syscall open
npm error path /home/node/.npm/_cacache/tmp/***
npm error errno EACCES
npm error Your cache folder contains root-owned files, due to a bug in previous versions of npm which has since been addressed.
npm error To permanently fix this problem, please run:
npm error sudo chown -R 1000:1000 "/home/node/.npm"When the failing path is the global folder, you get the generic message:
npm error code EACCES
npm error syscall mkdir
npm error path /usr/local/lib/node_modules/npm-check-updates
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/npm-check-updates'
npm error The operation was rejected by your operating system.
npm error It is likely you do not have the permissions to access this file as the current userWhy npm needs root in the first place#
npm writes to two places, and either one can be owned by root.
The cache. The npm folders documentation says cache files are stored in ~/.npm on POSIX systems. If the first npm command that ever touches that folder runs as root, root owns what it creates. The reproduction ran npm as root with HOME set to the normal user's home, as a stand-in for sudo (the Docker image has no sudo). On a fresh cache it left everything root-owned:
drwxr-xr-x 5 0 0 4096 Oct 11 01:55 _cacache
drwxr-xr-x 2 0 0 4096 Oct 11 01:55 _logsThat happened on npm 11.19.0, even though npm's own message calls this "a bug in previous versions of npm which has since been addressed". The next ordinary npm install in a project failed with the cache message above. npm picks that message in lib/utils/error-message.js: on a non-Windows system, an EACCES or EPERM whose path starts with the configured cache gets the chown advice, and anything else gets the generic "rejected by your operating system" text.
The global prefix. The same folders page says the prefix config "defaults to the location where node is installed. On most systems, this is /usr/local." On Unix, global packages go to {prefix}/lib/node_modules and their commands are linked into {prefix}/bin. An installer that puts Node.js into /usr/local as root leaves both folders owned by root:
/usr/local
drwxr-xr-x 1 root root 4096 Sep 9 18:47 /usr/local/bin
drwxr-xr-x 4 root root 4096 Sep 7 23:56 /usr/local/lib/node_modulesA local npm install inside your own project never touches the prefix. In the reproduction it worked without sudo once the cache was fixed, while the default prefix was still /usr/local. Only -g installs (and npm link) write there. Answer 2 on the Stack Overflow thread puts it this way: "You probably ran Node.js installation with root permissions, that's why the global package installation is asking you to be root."
Fix#
Fix the cache first if the path line points into ~/.npm, then pick one of the two ways to stop global installs from needing root. The npm guide on EACCES errors lists those two ways and recommends the version manager.
1. Give the cache back to your user#
This is the command npm prints itself. It is the one place where you still need sudo, once:
sudo chown -R "$(id -u):$(id -g)" ~/.npmIn the reproduction the same project install went through straight afterwards:
added 1 package, and audited 2 packages in 612msThis does not fix global installs. Immediately after the chown, npm install -g still failed with EACCES: permission denied, mkdir '/usr/local/lib/node_modules/npm-check-updates', because the cache was never the cause of that one.
2. Recommended: install Node.js with a version manager#
The npm guide calls reinstalling npm with a node version manager "the best way to avoid permissions issues". It also says you do not need to remove your current Node.js first. With nvm, Node.js and every global package live under ~/.nvm, which you own. Install nvm with the command from its README, open a new terminal, then:
nvm install 24
npm config get prefix
npm install -g npm-check-updates
command -v ncuThe prefix now points inside your home directory, and the global install needs no sudo. The reproduction used nvm v0.40.8 and ran these commands after removing the prefix left by the test in step 3 (see the nvm section below):
/home/node/.nvm/versions/node/v24.21.0
added 1 package in 324ms
/home/node/.nvm/versions/node/v24.21.0/bin/ncu3. Without a version manager: point the prefix at a folder you own#
The npm guide's manual route keeps the Node.js you already have. It tells npm to install global packages into ~/.local:
npm config set prefix ~/.localThat writes one line to ~/.npmrc (prefix=/home/node/.local in the reproduction). Then add the new bin folder to PATH in ~/.profile:
PATH=~/.local/bin:$PATHThe guide adds that zsh users also need source ~/.profile in ~/.zprofile. Reload the profile in the current terminal:
source ~/.profileSkip the PATH step and the install succeeds, but the command is not found. This is what the reproduction printed between the two steps:
bash: line 1: ncu: command not foundVerify the fix#
Run these as yourself, without sudo:
npm config get prefix
npm install -g npm-check-updates
ncu --version
command -v ncuThe prefix should be inside your home directory, the install should finish with "added 1 package", and command -v should print a path under that prefix. With the ~/.local prefix, the reproduction printed:
added 1 package in 6s
23.1.1
/home/node/.local/bin/ncuNothing was written to the system folder: ls -ld /usr/local/lib/node_modules/npm-check-updates answered "No such file or directory". If the error is still EACCES, read its path line again. A path inside ~/.npm means step 1 was skipped or ran on the wrong folder. A path under /usr/local means npm is still using the old prefix, so check npm config get prefix and which npm.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Chowning /usr/local/lib/node_modules is half a fix#
The third answer on the thread suggests sudo chown -R $USER /usr/local/lib/node_modules. On its own it moves the failure one step further. After that chown, with the default prefix, the reproduction failed on the command link instead:
npm error syscall symlink
npm error path ../lib/node_modules/npm-check-updates/build/cli.js
npm error dest /usr/local/bin/ncu
npm error Error: EACCES: permission denied, symlink '../lib/node_modules/npm-check-updates/build/cli.js' -> '/usr/local/bin/ncu'In the official Debian-based image, /usr/local/bin is still owned by root after that chown, and npm left nothing behind in node_modules. Wherever that folder belongs to root, the same failure follows. Taking ownership of both system folders is not one of the routes npm documents. A user prefix or a version manager gets the same result without changing system folders.
nvm refuses a prefix in ~/.npmrc#
The two fixes do not combine. If you set a prefix first and switch to nvm later, the prefix line left in ~/.npmrc makes nvm stop. In the reproduction, nvm install 24 printed this (loading nvm.sh in a new shell printed the same message, with --silent added to the suggested command):
Your user’s .npmrc file (${HOME}/.npmrc)
has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.
Run `nvm use --delete-prefix v24.21.0` to unset it.The check lives in nvm.sh. It also rejects a PREFIX or NPM_CONFIG_PREFIX environment variable that points outside nvm's own folders. Run the command it prints. It deletes the prefix line, after which the reproduction showed:
Now using node v24.21.0 (npm v11.19.0)Remove the ~/.local/bin line from your profile at the same time: under nvm, global commands are linked into the bin folder of the active Node.js version, so that line no longer serves anything.
Windows, Docker and the next error#
The prefix section of the npm guide "does not apply to Microsoft Windows". There the default prefix is %AppData%\npm, which is already inside your user profile. npm's Windows message for this error code says the file may be "already in use (by a text editor or antivirus), or that you lack permissions to access it", so check for a program holding the file before you look at permissions.
Inside a Dockerfile, the cause is usually an install that ran as root before a USER switch, and the fix is different. Fix EACCES: permission denied, mkdir node_modules/.cache covers that case. For tools you only use in one project, you do not need a global install at all. Install the tool locally and run it through an npm script, as in Fix tsc is not recognized: run the local compiler. On macOS, once permissions are fixed, a global package with a native addon can stop at the next hurdle. If the install now ends with gyp: No Xcode or CLT version detected!, continue with the node-gyp Xcode fix.
The thread dates from 2013, but the cause has not changed: a folder npm writes to belongs to root. Fix the cache once, move global installs to a folder you own, and stop typing sudo in front of npm.
Further reading: Fix MikroORM: global EntityManager instance is disallowed. Also see Fix npm EACCES: permission denied on package-lock.json.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix npm EACCES: permission denied on package-lock.json
Separate a local lockfile permission failure from cache and global-install errors, then fix the owner without changing the dependency tree.
Fix EACCES: permission denied, mkdir node_modules/.cache
Reproduced in Docker: why the cache directory cannot be created, the one-line Dockerfile move that fixes it, and why an old volume keeps the error alive after a rebuild.
Fix Docker npm EBADENGINE: Unsupported engine
Read the Required and Actual lines, distinguish npm self-upgrades from application installs, and stop a floating npm release breaking an unchanged Dockerfile.


