Cannot find module" in Code Node (JS) - v1.94.1 Docker (Alpine/Node20) - Extensive Troubleshooting Done (Python Works)

Hi n8n Community,

I’m encountering a persistent “Cannot find module” error when trying to use external JavaScript modules (like is-odd or pdf-lib) in the Code node. I’ve been through extensive troubleshooting and would appreciate any insights or help.

Describe the problem/error/question:

The Code node (JavaScript) consistently fails to load external npm modules, even simple ones like is-odd. This occurs despite N8N_FUNCTION_ALLOW_EXTERNAL being set (currently to * for testing, previously also with specific module lists).

Interestingly, if I switch the Code node to Python (Beta) mode, importing and using standard Python libraries like json and sys works perfectly. This suggests the issue is specific to the JavaScript/Node.js module loading mechanism.

What is the error message (if any)?

When the Code node (JavaScript) attempts require('is-odd'); with N8N_RUNNERS_ENABLED=false and N8N_DISABLE_SANDBOX=false (or true, see below), the n8n GUI typically shows:

JSON{ "errorMessage": "Cannot find module 'is-odd' [line X]", "errorDescription": "VMError", "errorDetails": {}, "n8nDetails": { "nodeName": "Code", "nodeType": "n8n-nodes-base.code", "nodeVersion": 2, "n8nVersion": "1.94.1 (Self Hosted)", "stackTrace": [ "VMError: Cannot find module 'is-odd'", " at Resolver.resolveFull (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/resolver.js:126:9)", " at Resolver.resolve (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/resolver.js:121:15)", " at resolve (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/nodevm.js:317:21)", " at VM2 Wrapper.apply (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/bridge.js:490:11)", " at requireImpl (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/setup-node-sandbox.js:90:19)", " at require (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/setup-node-sandbox.js:171:10)", " at /usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-nodes-base@file+packages+nodes-base_@[email protected]_asn1.js@5_12b981d6b49d407a163f4d5244314033/node_modules/n8n-nodes-base/dist/nodes/Code:X:Y", " ...", " at NodeVM.run (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/nodevm.js:497:23)" ] } }

(Line numbers X, Y in the GUI stack trace vary slightly based on the exact code in the node.)

Sometimes, the error.code in the returned JSON (when catching the error within the Code node) shows ENOTFOUND.

If N8N_RUNNERS_ENABLED=true, the stack trace points to /@n8n+task-runner/dist/js-task-runner/require-resolver.js instead of vm2 directly. The error remains “Cannot find module”.

Please share your workflow:

The test workflow is minimal:

  1. Start node
  2. Code node (JavaScript)

JSON{ "nodes": [ { "parameters": {}, "name": "Start", "type": "n8n-nodes-base.start", "typeVersion": 1, "position": [ 250, 300 ] }, { "parameters": { "language": "javascript", "jsCode": "// Test Code for 'is-odd'\nconsole.log(\"Code Node: Attempting to require 'is-odd'.\");\nconsole.log(\"NODE_PATH from process.env: \", process.env.NODE_PATH);\nconsole.log(\"N8N_FUNCTION_ALLOW_EXTERNAL from process.env: \", process.env.N8N_FUNCTION_ALLOW_EXTERNAL);\n\nlet output = {};\ntry {\n const isOdd = require('is-odd');\n output.moduleFound = true;\n output.isOddResult = isOdd(3);\n output.message = \"Module 'is-odd' successfully loaded and executed.\";\n console.log(\"Module 'is-odd' successfully loaded.\");\n} catch (error) {\n console.error(\"Error loading 'is-odd':\", error);\n output.moduleFound = false;\n output.error = {\n message: error.message,\n stack: error.stack,\n code: error.code\n };\n throw error; // Re-throw to mark node as failed and see error in GUI\n}\nreturn output;" }, "name": "Code", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 450, 300 ] } ], "connections": { "Start": { "main": [ [ { "node": "Code", "type": "main", "index": 0 } ] ] } } }

Share the output returned by the last node: As shown in the error message section, the Code node fails and the output typically includes the error object.

Information on your n8n setup:

  • n8n version: 1.94.1 (from Docker image n8nio/n8n:latest at the time of testing)
  • Database (default: SQLite): SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): Tested with N8N_RUNNERS_ENABLED=true and N8N_RUNNERS_ENABLED=false. The error persists in both modes, with stack traces pointing to task-runner or vm2respectively.
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker (initially via Unraid’s Docker management, now with a direct docker-compose setup for cleaner testing).
  • Operating system:
    • Host: Unraid OS (Slackware-based)
    • Container: Alpine Linux (from n8nio/n8n:1.94.1 image), Node.js v20.19.2

Relevant docker-compose.yml:

`YAMLservices:
n8n:
# build: /path/to/my/custom/Dockerfile # Tried with Dockerfile to npm install -g modules
image: n8nio/n8n:1.94.1 # Currently testing with base image
container_name: n8n
restart: unless-stopped
ports:
- “5678:5678”
environment:
- GENERIC_TIMEZONE=Europe/Berlin
- TZ=Europe/Berlin
- WEBHOOK_URL=https:///
- NODE_ENV=production
- N8N_LOG_LEVEL=debug
- N8N_FUNCTION_ALLOW_EXTERNAL=* # Also tested with specific list: pdf-lib,node-fetch,pdf-parse,is-odd,pdf2json
- N8N_FUNCTION_ALLOW_BUILTIN=fs
- N8N_RUNNERS_ENABLED=false # Tested with true and false
- N8N_DISABLE_SANDBOX=false # Tested with true and false
- NODE_PATH=/usr/local/lib/node_modules # Tested when attempting global install via Dockerfile
volumes:
- /mnt/cache/appdata/n8n:/home/node/.n8n # Host path permissions are 1000:1000 rwxrwxr-x
networks:
- n8n_network

networks:
n8n_network:
driver: bridge`

Summary of Troubleshooting Steps & Findings:

  • N8N_FUNCTION_ALLOW_EXTERNAL: Confirmed via env in container and console.log(process.env.N8N_FUNCTION_ALLOW_EXTERNAL) in Code node that the variable is correctly set and read by n8n.
  • Host Volume Permissions: Confirmed /mnt/cache/appdata/n8n on host is 1000:1000 with rwxrwxr-xpermissions.
  • Network Connectivity: Container can ping and wget from registry.npmjs.org.
  • Manual npm install in container: npm install is-odd works in /home/node/ (non-mounted path) but not in /usr/local/lib/node_modules/n8n (due to EUNSUPPORTEDPROTOCOL workspace: error, likely due to n8n’s monorepo structure).
  • Dockerfile npm install -g: Attempted to build a custom image installing is-odd, pdf-lib etc. globally using npm install -g. Modules appear in /usr/local/lib/node_modules inside the container. NODE_PATH was set to this directory. The “Cannot find module” error in Code node persisted.
  • N8N_RUNNERS_ENABLED: Error occurs whether true or false. Stack trace source changes accordingly.
  • N8N_DISABLE_SANDBOX: Setting to true (with runners false) still results in “Cannot find module ‘is-odd’” with a stack trace pointing to vm2/lib/resolver.js. This suggests N8N_DISABLE_SANDBOX=true might not fully bypass vm2’s module resolution or that the issue is even more fundamental.
  • Python Test: A Code node set to Python successfully imports and uses standard libraries (json, sys).
  • No Module Cache Found: No node_modules or .npm cache directories for the external modules are found within the mounted /home/node/.n8n directory.

Key Questions:

  1. Given N8N_DISABLE_SANDBOX=true and N8N_RUNNERS_ENABLED=false, and modules globally installed with NODE_PATH set, why would require('is-odd') still fail with a VMError pointing to vm2/lib/resolver.js? Does N8N_DISABLE_SANDBOX=true not fully bypass vm2 for module resolution?
  2. Where does n8n (v1.94.1, Node.js v20, Alpine) attempt to download/cache modules specified in N8N_FUNCTION_ALLOW_EXTERNAL when it’s not using globally installed ones? Why is this process failing silently (no download errors in logs, no cache files created in /home/node/.n8n)?
  3. Could the ENOTFOUND error code (seen intermittently in GUI for the JS error) provide a clue, despite network connectivity being verified for the container?
  4. Are there any known issues or specific configurations required for n8n’s JS module loading on Alpine Linux with Node.js v20 that could explain this behavior, especially when Python standard library imports work fine?

Any help or pointers would be greatly appreciated. This is a critical blocker for my PDF processing workflows.

Thank you!

Instead of installing modules globally, can you try running npm install is-odd (and others you need) inside the n8n user data folder (usually /home/node/.n8n). The Code node might only see modules installed locally there. After that, restart the n8n container and test again.
Also,
If the Code node sandbox blocks external modules, consider moving your logic to a “Function Item” node or use an external service (like a microservice or API) to handle PDF processing or other module-heavy tasks, then pass data back to n8n.

Let me know if this was helpful

1 Like

Hi Abrar_Sami,

Thanks for your quick reply and the suggestion to try installing the modules directly into the n8n user data folder (/home/node/.n8n)!

I followed your advice and did the following:

  1. docker exec -it n8n /bin/sh
  2. cd /home/node/.n8n
  3. npm install is-odd

The installation was successful, and I can confirm the is-odd module (and its dependency is-number) are now present in /home/node/.n8n/node_modules/, as shown by ls -la inside the container:

`~/.n8n $ ls -la node_modules/
total 8
drwxr-xr-x 1 node node 66 May 31 15:38 .
drwxrwxr-x 1 node node 324 May 31 15:40 …
-rw-r–r-- 1 node node 816 May 31 15:38 .package-lock.json
drwxr-xr-x 1 node node 72 May 31 15:38 is-number
drwxr-xr-x 1 node node 72 May 31 15:38 is-odd

~/.n8n $ ls -la node_modules/is-odd/
total 16
drwxr-xr-x 1 node node 72 May 31 15:38 .
drwxr-xr-x 1 node node 66 May 31 15:38 …
-rw-r–r-- 1 node node 1091 May 31 15:38 LICENSE
-rw-r–r-- 1 node node 3495 May 31 15:38 README.md
-rw-r–r-- 1 node node 543 May 31 15:38 index.js
-rw-r–r-- 1 node node 1381 May 31 15:38 package.json`

After restarting the n8n container, I ran my test workflow with the Code node attempting require('is-odd');. Unfortunately, the result is still the same:

n8n GUI Output:

JSON{ "errorMessage": "Cannot find module 'is-odd' [line X]", // X is the line number of the require() call "errorDescription": "VMError", "n8nDetails": { // ... (full details as previously posted) "stackTrace": [ "VMError: Cannot find module 'is-odd'", " at Resolver.resolveFull (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@[email protected]/node_modules/@n8n/vm2/lib/resolver.js:126:9)", // ... ] } }

This was tested with N8N_RUNNERS_ENABLED=false and N8N_DISABLE_SANDBOX=false (and also true for the sandbox, with the stack trace still pointing to vm2). The N8N_FUNCTION_ALLOW_EXTERNAL is set to * (and also tested with the specific module list).

So, even with the module physically present in /home/node/.n8n/node_modules/, the Code node’s require() within its execution context cannot find it.

As for your other suggestion, the “Function Item” node doesn’t resolve the core module loading issue. My current workaround for the original PDF extraction task is to use an external pdftk Docker container called via the Execute Command node, which works reliably.

However, it remains puzzling why the Code node’s JavaScript environment (v1.94.1, Docker, Alpine, Node.js v20) struggles so much with external npm modules, especially when Python standard library imports in the Code node (Python beta mode) work fine, and all typical troubleshooting steps (host volume permissions, network, N8N_FUNCTION_ALLOW_EXTERNAL, NODE_PATH with globally installed modules via Dockerfile) have been exhausted.

It seems the issue is very specific to how n8n’s JavaScript execution context (likely vm2) resolves or is provisioned with these external modules in this environment.

Thanks again for trying to help!

Best regards,
rewulff