External task runners: Internal "JS Task Runner" still spawns despite N8N_RUNNERS_MODE=external in v1.120.4

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:

  1. External runners register successfully: Registered runner "launcher-javascript"

  2. Internal runner also spawns: Registered runner "JS Task Runner"

  3. Code nodes execute on internal runner (which doesn’t have custom modules)

  4. 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

  1. 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
  1. External runner never receives execution requests (no logs appear when Code node runs)

  2. 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)

1 Like

Hello @Silver2, welcome to the :n8n: community!

What happens when you run a simple Code node with no external modules?!

Let’s first configure everything using the default settings to make sure the runner is connected and actually receives the tasks.

Once we confirm that it’s working correctly, you can add extra dependencies..
To do that, you’ll need to extend the n8nio/runners image..

You can find the steps here:

The Exact same thing is happening on my end, too, with the same thing happening in the n8n logs, as OP described:

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

n8n version: 1.122.5

UPDATE: opened a bug report.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.