Describe the problem/error/question
When using external task runners (N8N_RUNNERS_MODE=external), n8n spawns internal “JS Task Runner” alongside external runners and uses the internal runner to execute Code nodes, ignoring the NODE_FUNCTION_ALLOW_EXTERNAL configuration set for external runners.
Expected behavior: With N8N_RUNNERS_MODE=external, only external runners (launcher-javascript, launcher-python) should execute tasks and respect the NODE_FUNCTION_ALLOW_EXTERNAL=* setting.
Actual behavior:
-
External runners register successfully:
Registered runner "launcher-javascript" -
Internal runner also spawns:
Registered runner "JS Task Runner" -
Code nodes execute on internal runner (which doesn’t have custom modules)
-
External runner logs show:
Waiting for launcher's task offer to be accepted(never receives tasks)
What is the error message (if any)?
Error: Module 'get-a-joke' is disallowed
at /opt/runners/task-runner-javascript/dist/js-task-runner/require-resolver.js:16:27
The module is installed in the external runner container and accessible via NODE_PATH, but tasks execute on the internal runner which doesn’t have the module.
Please share your workflow
Docker Compose Configuration
docker-compose.yml:
services:
n8n:
image: n8nio/n8n:1.120.4
container_name: n8n
restart: always
ports:
- "5678:5678"
env_file:
- .env
environment:
- N8N_RUNNERS_ENABLED=true
- N8N_RUNNERS_MODE=external
- N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
- N8N_RUNNERS_AUTH_TOKEN=REDACTED_TOKEN
- N8N_NATIVE_PYTHON_RUNNER=false
- N8N_RUNNERS_N8N_CONCURRENCY=0
- N8N_BLOCK_ENV_ACCESS_IN_NODE=true
- DB_TYPE=postgresdb
# ... other DB and host config vars
volumes:
- n8n_data:/home/node/.n8n
networks:
- n8n-network
task-runners:
image: n8nio/runners:1.120.4
container_name: n8n-runners
restart: always
volumes:
- ./js_runner/node_modules:/home/runner/custom-libs/js/node_modules
- ./python_libs:/home/runner/custom-libs/python
environment:
- N8N_RUNNERS_TASK_BROKER_URI=http://n8n:5679
- N8N_RUNNERS_AUTH_TOKEN=REDACTED_TOKEN
- N8N_RUNNERS_ENABLED=javascript,python
- N8N_RUNNERS_JAVASCRIPT_ENABLED=true
- N8N_RUNNERS_JAVASCRIPT_DIR=/opt/runners/task-runner-javascript
- N8N_RUNNERS_JAVASCRIPT_HEALTH_CHECK_SERVER_PORT=5681
- NODE_FUNCTION_ALLOW_EXTERNAL=*
- NODE_FUNCTION_ALLOW_BUILTIN=*
- NODE_PATH=/home/runner/custom-libs/js/node_modules:/opt/runners/task-runner-javascript/node_modules
- N8N_RUNNERS_PYTHON_ENABLED=true
- N8N_RUNNERS_PYTHON_DIR=/opt/runners/task-runner-python
- N8N_RUNNERS_PYTHON_HEALTH_CHECK_SERVER_PORT=5682
- PYTHONPATH=/home/runner/custom-libs/python:/opt/runners/task-runner-python
depends_on:
- n8n
networks:
- n8n-network
.env:
NODE_FUNCTION_ALLOW_BUILTIN=*
NODE_FUNCTION_ALLOW_EXTERNAL=*
N8N_RUNNERS_STDLIB_ALLOW=*
N8N_RUNNERS_EXTERNAL_ALLOW=*
N8N_RUNNERS_ENABLED=true
```
## **Logs Showing the Issue**
**n8n startup logs:**
```
n8n Task Broker ready on 0.0.0.0, port 5679
Registered runner "launcher-javascript" (178dfb52f3f8f0db)
Registered runner "launcher-python" (7522bbf3415b6f1b)
...
Registered runner "JS Task Runner" (JMpjzhLjr4mOadfmZttx5) ← Internal runner spawns
...
Registered runner "launcher-javascript" (100b071fa17d92c7) ← External re-registers
Registered runner "JS Task Runner" (ncI8k4f0AysWyYRgIiIB_) ← Another internal spawns
```
**task-runners container logs:**
```
Starting launcher's health check server at port 5680
[launcher:js] Starting launcher goroutine...
[launcher:js] Waiting for task broker to be ready...
[launcher:js] Waiting for launcher's task offer to be accepted...
[launcher:js] Runner process exited on idle timeout ← Never receives tasks
Verification Steps
- Module exists and is accessible in external runner:
$ docker compose exec task-runners ls /home/runner/custom-libs/js/node_modules/get-a-joke
# ✅ Files exist
$ docker compose exec task-runners node -e "console.log(require.resolve('get-a-joke'))"
# ✅ Outputs: /home/runner/custom-libs/js/node_modules/get-a-joke/index.js
-
External runner never receives execution requests (no logs appear when Code node runs)
-
Tried disabling internal runners with:
-
N8N_NATIVE_PYTHON_RUNNER=false -
N8N_RUNNERS_N8N_CONCURRENCY=0 -
N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true -
N8N_BLOCK_ENV_ACCESS_IN_NODE=true
None prevent internal “JS Task Runner” from spawning.
-
Question
Is there a configuration to completely disable internal task runners when using N8N_RUNNERS_MODE=external, or is this a bug in v1.120.4 where external mode doesn’t fully prevent internal runner spawning?
Information on your n8n setup
-
n8n version: 1.120.4
-
Database: PostgreSQL 15
-
n8n EXECUTIONS_PROCESS setting: main
-
Running n8n via: Docker Compose
-
Operating system: Linux (Docker host)