Fix EACCES & Permission Denied in Linux — Node.js, npm, nvm
Summary: This guide helps you diagnose and fix common Linux "permission denied" and EACCES errors — from mkdir failures to Node.js directory creation errors and npm permission issues. Follow safe commands (no sudo hacks) and learn how to manage npm permissions with nvm.
Why "Permission denied" and EACCES happen on Linux
Linux enforces access through user IDs, group IDs and filesystem permission bits (rwx). When a process tries to create or write a file in a directory where its effective user lacks write or execute bits for that directory, the kernel returns EACCES (Permission denied). This shows up in commands like mkdir and in programs like Node.js when creating folders or writing modules.
Another frequent cause: ownership mismatch. Files or directories owned by root or another user will block writes from your unprivileged account. Processes started with different effective users (systemd services, Docker, or npm run scripts invoked with sudo) complicate the behavior further.
Finally, SELinux/AppArmor or immutable flags on files can block operations even when rwx bits look correct. Network filesystems (NFS, SMB) can also present different permission semantics, causing surprises for developers and CI pipelines.
Quick diagnostics: find the problem fast
Start by reproducing the error and capturing the exact message: "EACCES: permission denied, mkdir '/path/to/dir'" or "Error: EPERM". This exact wording helps pinpoint whether it's a filesystem, ownership, or process capability issue.
Check which user your process runs as with id or ps. For example, run id and ps -o user= -p $(pgrep -n node) to see the effective user for a node process. If a CI or service user is different than expected, the fix is usually ownership or a system configuration change.
Use ls -ld and stat to inspect directory permissions and ownership. Example: stat -c "%U %G %A %n" /path/to/dir and ls -ld /path/to/dir. If the directory lacks write (w) or execute (x) bits for the user or group, that's the cause.
- Check quick: id, whoami, ls -ld, stat, ps, pgrep
- Check logs: systemd journal, app logs, and npm output for EACCES
Fix: mkdir permission error and simple filesystem fixes
If mkdir fails with permission denied, the immediate fix is correcting ownership or permission bits for the parent folder. Use chown to set the owner and chmod to set correct bits. For example: sudo chown -R $(whoami):$(whoami) /path/to/project and chmod u+rwx /path/to/project.
A safer pattern in multi-user systems is adding your user to a group that owns the folder and granting group write permissions. Example: sudo usermod -aG deploygroup $(whoami) followed by sudo chgrp -R deploygroup /var/www && chmod -R g+rwX /var/www. This avoids giving blanket writable access to everyone.
If you're working on a shared or network mount, consult mount options and NFS/SMB UID/GID mapping. Sometimes the effective UID inside a container or VM doesn't match your host user, so chown may need to be applied from the container or the mount configured with proper uid/gid options.
Using chmod and chown correctly
Use chmod for changing permission bits (rwx) and chown to change ownership. Prefer symbolic modes for clarity: chmod u+rwx,g+rx,o-rwx
Use the execute (x) bit on directories to allow traversal. A common mistake is granting write but forgetting execute: chmod g+w /path/to/dir without x prevents entering the directory. Use chmod g+rwX to set X only where it makes sense (directories and already-executable files).
On Ubuntu systems EACCES permission denied Ubuntu specifics often relate to snaps, /var/www, or /home. Be explicit with chown: sudo chown -R username:group /target. Avoid running build tools with sudo as that creates root-owned artifacts that break later runs.
Node.js: directory creation error and EACCES in runtime
When Node.js throws EACCES during fs.mkdir or when npm tries to write to global directories, the root cause is usually a permissions mismatch for the target folder or global npm prefix. If your app writes to a system path like /usr/local/lib or /var, prefer configuring your app to use a user-writable path (e.g., ~/.local/share, /srv, or an explicitly owned data directory).
A typical Node.js directory creation error occurs when a library tries to create node_modules or build artifacts owned by root. If you previously used sudo with npm or yarn, files in node_modules may be root-owned, causing later node or npm commands to fail with EACCES.
Fix runtime errors by fixing ownership (chown) of the project directory and avoiding running node/npm with sudo. If a process legitimately needs elevated access (binding privileged ports, writing to /usr/local), use a dedicated service user or capabilities (setcap) instead of making everything root-writable.
npm permission issues on Linux and safe fixes
npm permission issues Linux users see often are global install failures (npm i -g) and EACCES during package installation. The root cause: npm's global prefix is set to a directory owned by root (common when Node was installed via apt). The safe fixes are to change npm's prefix or use a Node version manager.
Option 1: Configure a per-user global directory. Create ~/.npm-global, then run npm config set prefix '~/.npm-global' and add ~/.npm-global/bin to your PATH. This avoids sudo for global installs and keeps files under your user account.
Option 2: Use a version manager like nvm which installs Node and npm per-user. This is the recommended solution because it isolates Node versions and gives your user ownership of Node-related directories, eliminating most EACCES issues.
Managing npm permissions with nvm (recommended)
nvm installs Node and npm in your home directory and modifies PATH to use that user-local installation. When Node and npm live under your user, global npm operations no longer require sudo, and npm permission issues fade away. Install nvm and then install Node: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash && nvm install –lts.
With nvm you can switch Node versions per-shell or per-project, which prevents cross-project permission conflicts. If your CI needs reproducible behavior, use nvm in CI scripts or adopt Docker containers that pre-install the appropriate Node version under a non-root user.
For guidance, read the official nvm docs and the npm docs on permissions. See the nvm install page for platform-specific notes and troubleshooting steps to ensure your shell sources the nvm script correctly during login and non-login shells.
Preventive best practices
Never run development tools with sudo to "fix" permission errors. That habit creates root-owned files that break later runs and CI. Instead, fix ownership issues or adopt per-user installs and version managers.
Use group-based permissions on multi-user systems for collaboration. Create a group for project members, chgrp -R teamgroup /srv/project, and set g+rwX. Combine with umask or setgid bit on directories to keep group ownership consistent for newly created files.
Automate permission checks in setup scripts and CI to detect and fix problematic ownership before deployment. This includes verifying node_modules, build artifacts, and global npm packages for unexpected owners or sticky bits.
- Prefer nvm (per-user Node) over system-wide apt installations for development.
- Avoid sudo for npm; use npm config prefix or nvm to get user-writable directories.
Links and references (backlinks)
Practical references to deepen your fixes:
mcp-scholarly Linux compatibility — project-specific notes and environment details.
Node.js documentation — fs, permissions, and runtime behavior.
npm permissions — official guidance for prefix and global installs.
chmod chown permissions Linux — practical chmod/chown examples and pitfalls.
nvm managing npm permissions — nvm README and install instructions.
Semantic core (clustered keywords)
Primary: mcp-scholarly Linux compatibility; permission denied error Linux; EACCES permission denied Ubuntu; fix mkdir permission error Linux; chmod chown permissions Linux
Secondary: Node.js directory creation error; npm permission issues Linux; managing npm permissions with nvm; npm EACCES fix; global npm install permission denied
Clarifying / LSI: file ownership Linux, chown -R, chmod u+rwx, group permissions, SELinux EACCES, Node fs.mkdir EACCES, npm config set prefix, nvm install node, avoid sudo with npm
FAQ
Q1: How do I fix EACCES permission denied on Ubuntu when installing npm packages?
A1: Do not use sudo. Fix by either setting a per-user npm prefix (mkdir ~/.npm-global; npm config set prefix '~/.npm-global' and add ~/.npm-global/bin to PATH) or install Node with nvm so npm runs under your user. Alternatively, change ownership of the problematic directory with sudo chown -R $(whoami) /path/to/dir.
Q2: Why does Node.js throw "EACCES: permission denied, mkdir"?
A2: Because the process tried to create a directory where the effective user lacks write/traverse permission. Check ownership (ls -ld), ensure the directory exists, and fix with chown or chmod to grant write+execute to the appropriate user or group. Prefer using app-specific data directories owned by your app user.
Q3: Is using nvm the best way to manage npm permissions?
A3: Yes — for development environments, nvm is recommended. It installs Node/npm in your home directory, so global packages install without sudo and permission conflicts are minimized. For production, use dedicated service users or containers configured with proper ownership.