Hi everyone,
I’m struggling to get an external Python package (curl_cffi) working in my n8n setup. Despite setting the required environment variables, the Code Node keeps throwing a security violation:
Import of external package ‘curl_cffi’ is disallowed. Allowed external packages: none.
Describe the problem/error/question
What I have done so far:
Set the environment variables in both the n8n (main) and n8n-runners containers.
Verified that the variables are present inside the containers using docker exec n8n-main env | grep NODE.
Manually installed the package in the runner container via pip install --break-system-packages curl_cffi (for testing purposes).
Performed a full docker compose down and docker compose up -d --force-recreate.
Cleared browser cache and restarted the workflow. I have added the envorinment variable NODE_FUNCTION_ALLOW_EXTERNAL=curl_cffi both to n8n and n8n-runners. I have added N8N_NATIVE_PYTHON_RUNNER=true too.
The Issue:
Even though env shows the variables are set, n8n seems to ignore them for the Python validator. The error message specifically says “Allowed external packages: none”.
Is there a specific trick for Task Runners and Python external modules? Does the main node need to “see” the python package in its own environment just for validation, even if the runner is the one executing it?
Any help is much appreciated!
What is the error message (if any)?
Please share your workflow
Python Code node
Share the output returned by the last node
Security violations detected
Line 1: Import of external package ‘curl_cffi’ is disallowed. Allowed external packages: none
Information on your n8n setup
- n8n version: latest
- Database (default: SQLite): SQLite
- n8n EXECUTIONS_PROCESS setting (default: own, main): deafault
- Running n8n via (Docker, npm, n8n cloud, desktop app): docker
- Operating system: linux
1 Like
Hi @huhuhaha Welcome!
i guess for python external packages in n8n, you have to build a custom n8nio/runners image with uv pip install curl_cffi kind of built, with "N8N_RUNNERS_EXTERNAL_ALLOW": "curl_cffi" to /etc/n8n-task-runners.json inside the image , and then use this in your docker compose as your current NODE_FUNCTION_ALLOW_EXTERNAL won’t work for Python.
So what i would recommend is that going through this: (I also refer This)
i ran into a new problem: The ‘Multiple Runners’ Port Trap: As soon as you define both a javascript and a python runner in n8n-task-runners.json, the launcher becomes very strict. It throws an error: health-check-server-port is required with multiple runners
Thats my n8n-task-runners.json: {
“task-runners”: [
{
“runner-type”: “javascript”,
“env-overrides”: {
“NODE_FUNCTION_ALLOW_BUILTIN”: “",
“NODE_FUNCTION_ALLOW_EXTERNAL”: “lodash,axios”
}
},
{
“runner-type”: “python”,
“env-overrides”: {
“PYTHONPATH”: “/opt/runners/task-runner-python”,
“N8N_RUNNERS_STDLIB_ALLOW”: "”,
“N8N_RUNNERS_EXTERNAL_ALLOW”: “curl_cffi”
}
}
]
}
1 Like
@huhuhaha As far as i know you can add "health-check-server-port" for each runner entry in your n8n-task-runners.json as launcher requires unique ports and 2 services cannot be on one port simultaneously , like you can try something like this:
{
"task-runners": [
{
"runner-type": "javascript",
"health-check-server-port": 5680,
"env-overrides": {
"NODE_FUNCTION_ALLOW_BUILTIN": "",
"NODE_FUNCTION_ALLOW_EXTERNAL": "lodash,axios"
}
},
{
"runner-type": "python",
"health-check-server-port": 5681,
"env-overrides": {
"PYTHONPATH": "/opt/runners/task-runner-python",
"N8N_RUNNERS_STDLIB_ALLOW": "",
"N8N_RUNNERS_EXTERNAL_ALLOW": "curl_cffi"
}
}
]
}
and i suppose curl_cffi is already installed on the machine , if not you can do that via:
uv pip install curl_cffi
and install this in your docker file as manually installing it on a running container would not last. Give this a try
The problem is which environment variable controls Python packages vs JavaScript packages — they’re different.
For Python packages in the task runner:
You need N8N_RUNNERS_EXTERNAL_ALLOW (not NODE_FUNCTION_ALLOW_EXTERNAL, which is JavaScript only).
In your n8n-task-runners.json for the python runner:
{
"runner-type": "python",
"env-overrides": {
"PYTHONPATH": "/opt/runners/task-runner-python",
"N8N_RUNNERS_STDLIB_ALLOW": "*",
"N8N_RUNNERS_EXTERNAL_ALLOW": "curl_cffi"
}
}
And on the main n8n container side, you also need:
N8N_RUNNERS_EXTERNAL_ALLOW=curl_cffi
The main instance validates the allowed list at the n8n level before it even sends the code to the runner — that’s why you’re seeing “Allowed external packages: none” even though the runner has the package installed. Both sides need to agree.
Quick checklist:
N8N_RUNNERS_EXTERNAL_ALLOW=curl_cffi on both main n8n container AND the runner
- Package actually installed in the runner container (you did this with pip)
- Restart both containers after env changes
NODE_FUNCTION_ALLOW_EXTERNAL only applies to JavaScript Code nodes, not Python. Easy thing to mix up since the docs don’t make this super obvious.