parallax/jsPDF · error · Error
Cannot read file '${url}'. Permission denied.
Error message
Cannot read file '${url}'. Permission denied. What it means
When Node's permission model is active (process.permission exists), nodeReadFile checks process.permission.has('fs.read', url) against the resolved real path. If the Node allow-list does not cover that exact path, jsPDF throws 'Permission denied.' This check takes precedence over allowFsRead — even if allowFsRead lists the path, Node's deny wins.
Source
Thrown at src/modules/fileloading.js:150
if (!process.permission && !this.allowFsRead) {
throw new Error(
"Trying to read a file from local file system. To enable this feature either run node with the --permission and --allow-fs-read flags or set the jsPDF.allowFsRead property."
);
}
try {
url = fs.realpathSync(path.resolve(url));
} catch (e) {
if (sync) {
return undefined;
} else {
callback(undefined);
return;
}
}
if (process.permission && !process.permission.has("fs.read", url)) {
throw new Error(`Cannot read file '${url}'. Permission denied.`);
}
if (this.allowFsRead) {
const allowRead = this.allowFsRead.some(allowedUrl => {
const starIndex = allowedUrl.indexOf("*");
if (starIndex >= 0) {
const fixedPart = allowedUrl.substring(0, starIndex);
let resolved = path.resolve(fixedPart);
if (fixedPart.endsWith(path.sep) && !resolved.endsWith(path.sep)) {
resolved += path.sep;
}
return url.startsWith(resolved);
} else {
return url === path.resolve(allowedUrl);
}
});
if (!allowRead) {
throw new Error(`Cannot read file '${url}'. Permission denied.`);View on GitHub (pinned to a3930ce03a)
Solutions
- Add the resolved realpath (or its parent with a trailing slash) to node's --allow-fs-read list.
- Resolve symlinks before granting permission, or avoid symlinks in the asset path.
- Grant the directory: node --permission --allow-fs-read=./assets/ so all files under it are readable.
- Verify with process.permission.has('fs.read', require('fs').realpathSync(path)) before calling loadFile.
Example fix
// before // node --permission --allow-fs-read=./fonts app.js // requesting ./linked/Roboto.ttf -> symlink outside ./fonts -> throws [114] // after: allow the resolved directory // node --permission --allow-fs-read=./fonts --allow-fs-read=./linked app.js
Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const path = require('path');
function canReadViaNodePerm(url) {
if (!process.permission) return true; // model not active
let real;
try { real = fs.realpathSync(path.resolve(url)); } catch { return false; }
return process.permission.has('fs.read', real);
} Type guard
function nodePermActive() { return typeof process !== 'undefined' && !!process.permission; } Try / catch
try {
doc.loadFile(url, true);
} catch (e) {
if (/Permission denied/.test(e.message) && process.permission) {
// surface the missing --allow-fs-read flag to the operator; do not silently bypass
throw new Error('Add --allow-fs-read=' + require('path').dirname(require('fs').realpathSync(url)));
}
throw e;
} Prevention
- Run node with explicit --allow-fs-read flags for every asset directory.
- Resolve symlinks before granting permission; avoid symlinked asset paths.
- Test the permission grant with process.permission.has before calling loadFile.
When it happens
Trigger: Running `node --permission --allow-fs-read=./fonts` but requesting a file outside the allowed tree (e.g. ./secrets/key.pem, or a symlink resolving outside); allow-fs-read pattern that does not match the realpath returned by fs.realpathSync.
Common situations: Symlinks resolving outside the allowed directory; relative allow patterns vs absolute realpath mismatches; broadening read targets (new font folder) without updating the --allow-fs-read flags.
Related errors
- Trying to read a file from local file system. To enable this
- zoom must be Integer (e.g. 2), a percentage Value (e.g. 300%
- Page mode must be one of UseNone, UseOutlines, UseThumbs, or
- Layout mode must be one of continuous, single, twoleft, twor
- The option pdfobjectnewwindow just works in a browser-enviro
AI-assisted analysis of parallax/jsPDF@a3930ce03a (2026-08-13).
Data as JSON: /api/errors/e1c92f96c1469c1f.
Report an issue: GitHub.