N8N_RUNNERS_ENABLED=true breaks external module imports like JSDOM

Describe the problem/error/question

I am encountering issues when using third-party external libraries (specifically jsdom) within the Code node when Task Runners are enabled.

The workflow functions correctly when runners are disabled. However, enabling runners causes execution failures with different error messages depending on the configuration of NODE_FUNCTION_ALLOW_EXTERNAL.

This issue seems to persist across versions 1.119.2 and 1.121.3.

I have isolated three test cases:

  • Case 1 (Working): N8N_RUNNERS_ENABLED=false, NODE_FUNCTION_ALLOW_EXTERNAL=* → No Error
  • Case 2 (Failing): N8N_RUNNERS_ENABLED=true, NODE_FUNCTION_ALLOW_EXTERNAL=* → TypeError: Cannot assign to read only property ‘toString’
  • Case 3 (Failing): N8N_RUNNERS_ENABLED=true, NODE_FUNCTION_ALLOW_EXTERNAL=jsdom → EvalError: Code generation from strings disallowed for this context

What is the error message (if any)?

For Case 2 (Runners=true, External=*):
TypeError: Cannot assign to read only property 'toString' of object '#<Object>'

For Case 3 (Runners=true, External=jsdom):
EvalError: Code generation from strings disallowed for this context

Please share your workflow

Share the output returned by the last node

Output for Case 2:

{
  "errorMessage": "Cannot assign to read only property 'toString' of object '#<Object>'",
  "errorDetails": {},
  "n8nDetails": {
    "n8nVersion": "1.121.3 (Self Hosted)",
    "binaryDataMode": "default",
    "stackTrace": [
      "TypeError: Cannot assign to read only property 'toString' of object '#<Object>'",
      "    at /usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/decimal.js/decimal.js:2439:14",
      "    at Object.<anonymous> (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/decimal.js/decimal.js:4934:3)",
      "    at Module._compile (node:internal/modules/cjs/loader:1706:14)",
      "    at Object..js (node:internal/modules/cjs/loader:1839:10)",
      "    at Module.load (node:internal/modules/cjs/loader:1441:32)",
      "    at Function._load (node:internal/modules/cjs/loader:1263:12)",
      "    at TracingChannel.traceSync (node:diagnostics_channel:328:14)",
      "    at wrapModuleLoad (node:internal/modules/cjs/loader:237:24)",
      "    at Module.require (node:internal/modules/cjs/loader:1463:12)",
      "    at require (node:internal/modules/helpers:147:16)"
    ]
  }
}

Output for Case 3:

{
  "errorMessage": "Code generation from strings disallowed for this context",
  "errorDetails": {},
  "n8nDetails": {
    "n8nVersion": "1.121.3 (Self Hosted)",
    "binaryDataMode": "default",
    "stackTrace": [
      "EvalError: Code generation from strings disallowed for this context",
      "    at Function (<anonymous>)",
      "    at compile (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/nwsapi/src/nwsapi.js:760:17)",
      "    at collect (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/nwsapi/src/nwsapi.js:1539:22)",
      "    at _querySelectorAll (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/nwsapi/src/nwsapi.js:1499:36)",
      "    at Object._querySelector [as first] (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected]/node_modules/nwsapi/src/nwsapi.js:1405:14)",
      "    at DocumentImpl.querySelector (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js:69:44)",
      "    at exports.documentBaseURL (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/jsdom/lib/jsdom/living/helpers/document-base-url.js:8:30)",
      "    at exports.parseURLToResultingURLRecord (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/jsdom/lib/jsdom/living/helpers/document-base-url.js:41:27)",
      "    at fetchAndProcess (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js:86:15)",
      "    at maybeFetchAndProcess (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js:74:3)"
    ]
  }
}

Information on your n8n setup

  • n8n version: 1.121.3 (also reproduced on 1.119.2)
  • Database (default: SQLite): Postgresql 18
  • n8n EXECUTIONS_PROCESS setting (default: own, main): default
  • Running n8n via (Docker, npm, n8n cloud, desktop app): docker
  • Operating system: Ubuntu 25.10

Other configurations tested without good results (same error):

Config 01:

- NODE_FUNCTION_ALLOW_EXTERNAL=jsdom
- NODE_FUNCTION_ALLOW_BUILTIN=*
- N8N_RUNNERS_ENABLED=true
- N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION=true

Config 02:

- NODE_FUNCTION_ALLOW_EXTERNAL=jsdom
- NODE_FUNCTION_ALLOW_BUILTIN=*
- N8N_RUNNERS_ENABLED=true
- NODE_PATH=/usr/local/lib/node_modules

Config 03:

- NODE_FUNCTION_ALLOW_EXTERNAL=jsdom
- NODE_FUNCTION_ALLOW_BUILTIN=*
- N8N_RUNNERS_ENABLED=true
- N8N_NODE_PATH=/usr/local/lib/node_modules

Config 04:

- NODE_FUNCTION_ALLOW_EXTERNAL=jsdom
- NODE_FUNCTION_ALLOW_BUILTIN=*
- N8N_RUNNERS_ENABLED=true
- N8N_NODE_PATH=/usr/local/lib/node_modules
- N8N_REINSTALL_MISSING_PACKAGES=true

Config 05:

- NODE_FUNCTION_ALLOW_EXTERNAL=jsdom
- NODE_FUNCTION_ALLOW_BUILTIN=*
- N8N_RUNNERS_ENABLED=true
- N8N_NODE_PATH=/usr/local/lib/node_modules
- NODE_PATH=/usr/local/lib/node_modules
- N8N_RUNNERS_ALLOW_PROTOTYPE_MUTATION=true
- N8N_REINSTALL_MISSING_PACKAGES=true

None of this configurations allow the JSDOM third party (external) library to work.

The only way to make it work is to set N8N_RUNNERS_ENABLED=false.

Any idea how to enable runners and allow external JavaScript libraries?

2 Likes

For some reason I can’t see a response that have arrived by email. This is the response:

Hey,

The issues you’re encountering with jsdom when N8N_RUNNERS_ENABLED=true are due to how external modules are sandboxed within the dedicated runner process.

Case 2’s TypeError: Cannot assign to read only property ‘toString’ suggests an incompatibility or strict mode issue within decimal.js (a dependency of jsdom) when loaded in the runner environment. Case 3’s EvalError: Code generation from strings disallowed for this context indicates the runner’s sandbox disallows dynamic code evaluation, which jsdom’s underlying selector engine (nwsapi) attempts to use.

These are common limitations with complex external libraries in a sandboxed execution environment. jsdom performs operations that are often restricted for security and stability reasons in such contexts.

Consider using a dedicated external service or a custom Node.js application for jsdom processing, triggered via an HTTP Request node, rather than attempting to run it directly within an n8n Code node with runners enabled.

Best,

I was trying to replace jsdom with another library but I couldn’t find a good replacement.

I really like the idea to have an increased security, but right now the options that I have are:

  • Continue using jsdom which implies I can’t enable runners and I can’t update the n8n instance, making the whole solution less secure. This is an option that I can “implement” right now.
  • Dedicated service or custom app to replace jsdom, to enable runners and updates. This is an option that requires more time to implement.

I would like to have an option to lower the security in the runners, or in the runner that processes this code, to run jsdom knowing that it doesn’t fit the security standards.

I’m aware that this problem is not only affecting to jsdom library but also other people using other libraries.