Skip to content

Docker: uv creates .venv in mounted project directory, breaking container startup #12616

@nikblanchet

Description

@nikblanchet

Details

When running inv docker.up after a fresh inv docker.build, containers fail to start with ModuleNotFoundError errors (e.g., "No module named 'django'", "No module named celery").

The Dockerfile creates a virtualenv at /.venv and installs dependencies there:

ENV VIRTUAL_ENV="/.venv"
RUN uv venv $VIRTUAL_ENV
RUN uv pip sync docker.txt

However, when uv run executes inside the container, it ignores VIRTUAL_ENV=/.venv and instead looks for .venv in the project directory (which is mounted from the host). This warning appears:

warning: `VIRTUAL_ENV=/.venv` does not match the project environment path `.venv` and will be ignored

If there's no .venv on the host, uv creates one in the mounted volume. This persists on the host and causes issues on subsequent runs because:

  1. The host's .venv is incomplete (created by the container but not populated correctly)
  2. It shadows the container's /.venv where dependencies are actually installed

Evidence that the .venv was created by the container (from pyvenv.cfg):

home = /usr/bin          # Linux path, not macOS
uv = 0.9.11
prompt = readthedocs-local-dev

Expected Result

inv docker.up should start all containers successfully using the /.venv created during docker build.

Actual Result

Containers crash with module import errors:

celery_1  | /usr/src/app/checkouts/readthedocs.org/.venv/bin/python3: No module named celery
celery_1  | [nodemon] app crashed - waiting for file changes before starting...
web_1  | ModuleNotFoundError: No module named 'django'

Why this may not affect all developers

Developers who previously ran uv sync locally (e.g., for IDE support or local testing) would have a fully populated .venv on their host. When mounted into the container, this happens to work, but it's fragile and depends on the local .venv staying in sync with container requirements.

Workaround

Create a symlink on the host pointing to the container's venv:

ln -s /.venv .venv

This makes uv run find the correct virtualenv inside the container.

Possible Fixes

  1. Add .venv to .dockerignore to prevent mounting
  2. Use uv run --active to respect the VIRTUAL_ENV environment variable
  3. Create the symlink as part of container entrypoint
  4. Pin uv to an older version that respects VIRTUAL_ENV

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions