`unit-python3.11`:`ModuleNotFoundError: No module named '_contextvars'` with non-root user and `uv`
Bug Overview
I have a Python project that uses uv. When I install uv and set up the virtual environment using a non-root user, nginx-unit won't apply the configuration:
curl -X PUT --data-binary @/path/to/project/config.json --unix-socket /var/run/control.unit.sock http://localhost/config/
{
"error": "Failed to apply new configuration."
}
The log reveals:
Traceback (most recent call last):
File "/path/to/app/src/app/project/wsgi.py", line 3, in <module>
from django.core.wsgi import get_wsgi_application
File "/path/to/app/.venv/lib/python3.11/site-packages/django/core/wsgi.py", line 2, in <module>
from django.core.handlers.wsgi import WSGIHandler
File "/path/to/app/.venv/lib/python3.11/site-packages/django/core/handlers/wsgi.py", line 3, in <module>
from django.conf import settings
File "/path/to/app/.venv/lib/python3.11/site-packages/django/conf/__init__.py", line 19, in <module>
from django.utils.deprecation import RemovedInDjango60Warning
File "/path/to/app/.venv/lib/python3.11/site-packages/django/utils/deprecation.py", line 4, in <module>
from asgiref.sync import iscoroutinefunction, markcoroutinefunction, sync_to_async
File "/path/to/app/.venv/lib/python3.11/site-packages/asgiref/sync.py", line 1, in <module>
import asyncio
File "/home/myuser/.local/share/uv/python/cpython-3.11.12-linux-x86_64-gnu/lib/python3.11/asyncio/__init__.py", line 8, in <module>
from .base_events import *
File "/home/myuser/.local/share/uv/python/cpython-3.11.12-linux-x86_64-gnu/lib/python3.11/asyncio/base_events.py", line 41, in <module>
from . import events
File "/home/myuser/.local/share/uv/python/cpython-3.11.12-linux-x86_64-gnu/lib/python3.11/asyncio/events.py", line 18, in <module>
import contextvars
File "/home/myuser/.local/share/uv/python/cpython-3.11.12-linux-x86_64-gnu/lib/python3.11/contextvars.py", line 1, in <module>
from _contextvars import Context, ContextVar, Token, copy_context
ModuleNotFoundError: No module named '_contextvars'
I think it's important to note I was able to have it up and running a couple of times:
- The first time I accidentally ran everything as root (installed uv, set up the venv etc.) then
chown-ed the app directory tounit, and that worked. - The second time, I gave up on
uvand used the system Python to set up the env asmyuseretc. and that worked.
Now I'm back to trying to set everything up as myuser. I re-ran just to be sure:
chown -R myuser:mygroup /path/to/app/
chmod -R u+rwx /path/to/app/
Given _contextvars is definitely not missing from either system-Python or uv-Python, and that it worked when I set everything up as root, I'm now inclined to think it's a permissions issue. The error message and traceback are not giving away that much, though.
There's an older discussion that appears to be similar - https://github.com/nginx/unit/issues/516 - and if I understand it correctly, the issue there is the unit user doesn't have sufficient access to the venv. I added unit to the group (usermod -a -G unit mygroup) and changed permissions (chmod -R g+rwx /path/to/app/):
$ ls -la /path/to/app/.venv/
total 32
drwxrwxr-x 5 myuser mygroup 4096 Jun 3 09:20 .
drwxrwxr-x 5 myuser mygroup 4096 Jun 3 09:19 ..
-rwxrwxr-- 1 myuser mygroup 1 Jun 3 09:19 .gitignore
-rwxrwxr-- 1 myuser mygroup 43 Jun 3 09:19 CACHEDIR.TAG
drwxrwxr-x 2 myuser mygroup 4096 Jun 3 09:20 bin
drwxrwxr-x 3 myuser mygroup 4096 Jun 3 09:20 include
drwxrwxr-x 3 myuser mygroup 4096 Jun 3 09:19 lib
lrwxrwxrwx 1 myuser mygroup 3 Jun 3 09:19 lib64 -> lib
-rwxrwxr-- 1 myuser mygroup 191 Jun 3 09:19 pyvenv.cfg
That didn't do the trick.
Expected Behavior
I'm expecting it to work.
Steps to Reproduce the Bug
uv python install 3.11.12
uv venv --python 3.11.12
etc.
Environment Details
- Target deployment platform: VPS
- Target OS: Debian 12
- Version of this project or specific commit: unit 1.34.2
- Version of any relevant project languages: Python (system) 3.11.2, uv 0.7.9, uv Python (uv) 3.11.12
Additional Context
Fwiw, config.json looks like:
{
"listeners": {
"*:9001": {
"pass": "routes"
}
},
"routes": [
{
"action": {
"pass": "applications/app"
}
}
],
"applications": {
"app": {
"type": "python",
"user": "myuser",
"group": "mygroup",
"path": "/path/to/app/",
"home": "/path/to/app/.venv/",
"module": "app.project.wsgi",
"callable": "application",
"environment": {
etc.
}
}
}
}
Exact same issue here.
EDIT: I figured out what the problem was. Turns out it's not a compatibility or permission issue when using uv and unit - it's a conflict between the unit-python version and the python version used when creating your virtual environment.
In my case I had a python3.12 venv, but was loading unit-python3.10 in my Dockerfile.
I simply went in my pyproject.toml and changed my python version 3.10:
requires-python = "==3.10.*"
Now when I rebuild my docker container - my venv is using the same version as unit-python and my unit configuration loaded just fine. Hope this helps OP too.
@Pavel-Hadzhiyski thanks for your input, and I apologise for the late reply -- I believe I missed your edit. I need to ask: were you building the venv with system Python, or uv Python?