01
Read the failing path and operation
EACCES can concern a project directory, global prefix, cache, or other filesystem entry. Identify the path in the error rather than applying a cache repair to every permissions failure.
In our controlled test, the project directory was owned by node and the local tarball was readable. Only the selected cache was root-only. The non-root install therefore isolated a cache-access failure from an unwritable project tree.
02
Compare cache selection and identity
Inspect the effective cache path in the same environment and under the same user as the failing install. A shell outside a container can have a different identity and cache configuration.
The following POSIX commands reveal selected diagnostic values without printing npm registry tokens. Inspect directory ownership and permissions locally for the exact failing path.
id
npm config get cache
# Inspect ownership and permissions of the exact path in the EACCES error.03
Repair the intended boundary
For a persistent cache volume, align its ownership and permissions with the runner identity through the normal container or CI setup. If the environment should use a separate user-owned cache, choose that path explicitly.
The command below illustrates an isolated cache for a disposable verification run. Changing cache location can require downloading missing packages in a real project; the lab used local tarballs and no network.
# In a disposable checkout; /tmp is writable by this test user:
npm ci --cache /tmp/project-npm-cache --ignore-scripts04
Verify as the same user
The corrected lab install ran as node, used its own writable cache, and loaded the expected fixture dependency. No sudo command, world-writable mode, or host filesystem ownership change was used.
For the actual runner, repeat a clean install under the intended identity and confirm both cache and project writes work. A successful root-run retry would not establish that the original non-root process is repaired.
05
Keep global-install errors separate
If the original EACCES path belongs to a global package prefix rather than the cache, investigate that prefix and installation model separately. Cache permissions do not repair an unrelated protected system directory.
Avoid recursively changing ownership of an entire home or system directory based on one error line. Preserve the failure path, runner identity, cache selection, and verification outcome so the next job does not recreate the ownership mismatch.
Know the limits
Reproduced with npm 12.2.1 and Node.js 24.22.1 in a disposable Linux container using local fixtures, with external networking disabled during tests. A node-user install failed against an intentionally root-only test cache. Using a separate cache writable by that same user allowed installation and module loading. No host ownership, real shared cache, registry account, or global installation was changed.
Sources & further reading
A technical publication by CoreTrailKit.
Browse all articles