{"record":{"id":"e1c92f96c1469c1f","repo":"parallax/jsPDF","slug":"cannot-read-file-url-permission-denied","errorCode":null,"errorMessage":"Cannot read file '${url}'. Permission denied.","messagePattern":"Cannot read file '(.+?)'\\. Permission denied\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/modules/fileloading.js","lineNumber":150,"sourceCode":"    if (!process.permission && !this.allowFsRead) {\n      throw new Error(\n        \"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.\"\n      );\n    }\n\n    try {\n      url = fs.realpathSync(path.resolve(url));\n    } catch (e) {\n      if (sync) {\n        return undefined;\n      } else {\n        callback(undefined);\n        return;\n      }\n    }\n\n    if (process.permission && !process.permission.has(\"fs.read\", url)) {\n      throw new Error(`Cannot read file '${url}'. Permission denied.`);\n    }\n\n    if (this.allowFsRead) {\n      const allowRead = this.allowFsRead.some(allowedUrl => {\n        const starIndex = allowedUrl.indexOf(\"*\");\n        if (starIndex >= 0) {\n          const fixedPart = allowedUrl.substring(0, starIndex);\n          let resolved = path.resolve(fixedPart);\n          if (fixedPart.endsWith(path.sep) && !resolved.endsWith(path.sep)) {\n            resolved += path.sep;\n          }\n          return url.startsWith(resolved);\n        } else {\n          return url === path.resolve(allowedUrl);\n        }\n      });\n      if (!allowRead) {\n        throw new Error(`Cannot read file '${url}'. Permission denied.`);","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/parallax/jsPDF/blob/a3930ce03a585a26b2c76d12a0f413ce96f6d1a3/src/modules/fileloading.js#L132-L168","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// node --permission --allow-fs-read=./fonts app.js\n// requesting ./linked/Roboto.ttf -> symlink outside ./fonts -> throws [114]\n\n// after: allow the resolved directory\n// node --permission --allow-fs-read=./fonts --allow-fs-read=./linked app.js","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst path = require('path');\nfunction canReadViaNodePerm(url) {\n  if (!process.permission) return true; // model not active\n  let real;\n  try { real = fs.realpathSync(path.resolve(url)); } catch { return false; }\n  return process.permission.has('fs.read', real);\n}","typeGuard":"function nodePermActive() { return typeof process !== 'undefined' && !!process.permission; }","tryCatchPattern":"try {\n  doc.loadFile(url, true);\n} catch (e) {\n  if (/Permission denied/.test(e.message) && process.permission) {\n    // surface the missing --allow-fs-read flag to the operator; do not silently bypass\n    throw new Error('Add --allow-fs-read=' + require('path').dirname(require('fs').realpathSync(url)));\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["node","security","permissions","filesystem","fileloading","config"],"backgroundTag":null,"analyzedSha":"a3930ce03a585a26b2c76d12a0f413ce96f6d1a3","analyzedAt":"2026-08-13T05:33:39.648Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}