ERR_ACCESS_DENIED
Node.jsERRORCommonPermissionsHIGH confidence

Access denied by the Node.js permission model

Production Risk

The permission model is a security feature; ERR_ACCESS_DENIED indicates a least-privilege violation that should be audited.

What this means

Thrown when an operation is blocked by the Node.js Permission Model. Introduced in Node.js 20, the Permission Model allows restricting what file system paths, network access, child processes, and other resources a Node.js process can use. Attempting an operation outside the granted permissions throws ERR_ACCESS_DENIED.

Why it happens
  1. 1Reading a file path not covered by --allow-fs-read
  2. 2Writing to a path not covered by --allow-fs-write
  3. 3Spawning a child process when --allow-child-process is not granted
  4. 4Accessing the network without --allow-net
How to reproduce

Triggered whenever a restricted operation is attempted and the Permission Model is active.

trigger — this will error
trigger — this will error
// Run with: node --experimental-permission --allow-fs-read=/tmp app.js
const fs = require('fs');
fs.readFileSync('/etc/passwd'); // not in allowed paths — throws ERR_ACCESS_DENIED

expected output

Error [ERR_ACCESS_DENIED]: Access to this API has been restricted

Fix 1

Grant the required permission via CLI flags

WHEN When the permission model is active and the operation is legitimate

Grant the required permission via CLI flags
# Allow reading /etc/passwd explicitly
node --experimental-permission \
  --allow-fs-read=/tmp \
  --allow-fs-read=/etc/passwd \
  app.js

Why this works

Adding the specific path to the allow list grants the process access while keeping other paths restricted.

Fix 2

Restructure the app to only access permitted paths

WHEN When adopting the permission model for security hardening

Restructure the app to only access permitted paths
// Store configs in /tmp/app/ instead of /etc/
const config = JSON.parse(fs.readFileSync('/tmp/app/config.json', 'utf8'));

Why this works

Moving resources to permitted paths allows the permission model to be more restrictive.

Code examples
Triggerjs
// Run with: node --experimental-permission --allow-fs-read=/tmp app.js
const fs = require('fs');
fs.readFileSync('/etc/passwd'); // not in allowed paths — throws ERR_ACCESS_DENIED  // this triggers ERR_ACCESS_DENIED
Handle in try/catchjs
try {
  // operation that may throw ERR_ACCESS_DENIED
  riskyOperation()
} catch (err) {
  if (err.code === 'ERR_ACCESS_DENIED') {
    console.error('ERR_ACCESS_DENIED:', err.message)
  } else {
    throw err
  }
}
Defensive pattern to avoid itjs
// Validate inputs before calling the operation
function safe_err_access_denied(...args) {
  // validate args here
  return performOperation(...args)
}
What not to do

Use --allow-fs-read=* to bypass the permission model

A wildcard grant defeats the purpose of the permission model; grant only what is needed.

Sources
Official documentation ↗

Node.js Error Codes Documentation

Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev

← All Node.js errors