astral-sh/uv · error · AssertionError

You must use import runpy; runpy.run_path(this_file)

Error message

You must use import runpy; runpy.run_path(this_file)

What it means

`activate_this.py` is the template uv-virtualenv writes into `<venv>/bin/` for in-process activation. It computes `base` from `__file__`, so it must run as a file, not as a bare code string. The `try: abs_file = os.path.abspath(__file__)` catches the NameError raised when `__file__` is undefined and re-raises it as an AssertionError telling you the supported invocation: `runpy.run_path(this_file)`.

Source

Thrown at crates/uv-virtualenv/src/activator/activate_this.py:41

Activate virtualenv for current interpreter:

import runpy
runpy.run_path(this_file)

This can be used when you must use an existing Python interpreter, not the virtualenv bin/python.
"""  # noqa: D415

from __future__ import annotations

import os
import site
import sys

try:
    abs_file = os.path.abspath(__file__)
except NameError as exc:
    msg = "You must use import runpy; runpy.run_path(this_file)"
    raise AssertionError(msg) from exc

bin_dir = os.path.dirname(abs_file)
base = bin_dir[: -len("{{ BIN_NAME }}") - 1]  # strip away the bin part from the __file__, plus the path separator

# prepend bin to PATH (this file is inside the bin directory)
os.environ["PATH"] = os.pathsep.join([bin_dir, *os.environ.get("PATH", "").split(os.pathsep)])
os.environ["VIRTUAL_ENV"] = base  # virtual env is right above bin directory
os.environ["VIRTUAL_ENV_PROMPT"] = "{{ VIRTUAL_PROMPT }}" or os.path.basename(base)  # noqa: SIM222

# add the virtual environments libraries to the host python import mechanism
prev_length = len(sys.path)
for lib in "{{ RELATIVE_SITE_PACKAGES }}".split(os.pathsep):
    path = os.path.realpath(os.path.join(bin_dir, lib))
    site.addsitedir(path)
sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]

sys.real_prefix = sys.prefix
sys.prefix = base

View on GitHub (pinned to f1a42680ff)

Solutions

  1. Use runpy so `__file__` is defined: `import runpy; runpy.run_path("/path/to/.venv/bin/activate_this.py")`.
  2. Prefer out-of-process activation (`source .venv/bin/activate` or `uv run`) when you control the shell.
  3. If you must exec source text, pass a filename: `exec(compile(source, activate_path, "exec"), {"__file__": activate_path})`.

Example fix

# before
exec(open("/path/to/.venv/bin/activate_this.py").read())
# AssertionError: You must use import runpy; runpy.run_path(this_file)

# after
import runpy
runpy.run_path("/path/to/.venv/bin/activate_this.py")
Defensive patterns

Strategy: validation

Validate before calling

def activate_venv_inprocess(activate_this: str) -> None:
    # Reject exec-based activation before it fails cryptically
    import os
    assert os.path.isfile(activate_this), f"missing {activate_this}"
    import runpy
    runpy.run_path(activate_this)  # defines __file__ correctly

Type guard

def is_runpy_safe() -> bool:
    """True when __file__ is defined, i.e. run via run_path/run_module rather than exec(code)."""
    return "__file__" in globals()

Try / catch

try:
    exec(compile(source, path, "exec"), {"__file__": path})
except (AssertionError, NameError) as exc:
    if "runpy" in str(exc):
        import runpy
        runpy.run_path(path)
    else:
        raise

Prevention

When it happens

Trigger: Executing the script via `exec(open(".../activate_this.py").read())` (the snippet from virtualenv's docs) against a uv-created venv: `exec` compiles the code without a filename, so `__file__` is never bound and the NameError handler fires. Also `compile()`+`eval()` of the file contents, or any embedding that passes source text instead of a path.

Common situations: IDE run-configurations and PyCharm-style activation tasks, bootstrap scripts copied from virtualenv documentation, tox/nox activation helpers, or embedding code that activates a venv in-process; these worked with old virtualenv builds (which tolerated exec) but hit the explicit assertion with uv venvs.

Related errors


AI-assisted analysis of astral-sh/uv@f1a42680ff (2026-08-16). Data as JSON: /api/errors/c621674be4312672. Report an issue: GitHub.