astral-sh/uv · error · RuntimeError
{uv_bin_name} was not properly installed
Error message
{uv_bin_name} was not properly installed What it means
The `uv_build` PEP 517/660 backend is a thin Python shim: every hook (build_sdist, build_wheel, build_editable, ...) calls `call()`, which shells out to the `uv-build` executable (or `uv build-backend` when the distro sets USE_UV_EXECUTABLE=True). PEP 517 frontends run hooks in an isolated subprocess, so the shim cannot use `find_uv_bin`; it relies on `shutil.which(uv_bin_name)`. If that returns None the shim raises RuntimeError to fail fast instead of producing a confusing FileNotFoundError about a missing command.
Source
Thrown at crates/uv-build/python/uv_build/__init__.py:51
if config_settings:
print("Warning: Config settings are not supported", file=sys.stderr)
def call(
args: "Sequence[str]", config_settings: "Mapping[Any, Any] | None" = None
) -> str:
"""Invoke a uv subprocess and return the filename from stdout."""
import shutil
import subprocess
import sys
warn_config_settings(config_settings)
uv_bin_name = "uv" if USE_UV_EXECUTABLE else "uv-build"
# Unlike `find_uv_bin`, this mechanism must work according to PEP 517
uv_bin = shutil.which(uv_bin_name)
if uv_bin is None:
raise RuntimeError(f"{uv_bin_name} was not properly installed")
build_backend_args = ["build-backend"] if USE_UV_EXECUTABLE else []
# Forward stderr, capture stdout for the filename
result = subprocess.run(
[uv_bin, *build_backend_args, *args], stdout=subprocess.PIPE, check=False
)
if result.returncode != 0:
sys.exit(result.returncode)
# If there was extra stdout, forward it (there should not be extra stdout)
stdout = result.stdout.decode("utf-8").strip().splitlines(keepends=True)
sys.stdout.writelines(stdout[:-1])
# Fail explicitly instead of an irrelevant stacktrace
if not stdout:
print(
f"{uv_bin_name} subprocess did not return a filename on stdout",
file=sys.stderr,
)
sys.exit(1)
return stdout[-1].strip()View on GitHub (pinned to f1a42680ff)
Solutions
- In the same environment run `python -c "import shutil; print(shutil.which('uv-build'))"` (or 'uv') to confirm the lookup fails and see which binary name is expected.
- Install uv properly so the executable lands in the interpreter's scripts dir: `python -m pip install uv-build` (or the official installer), then prepend that scripts dir to PATH.
- If build isolation strips PATH, install the backend in the outer env and build with `--no-build-isolation` (`pip install --no-build-isolation -e .`).
- For downstream distributions: keep `uv` on PATH if you build with USE_UV_EXECUTABLE=True, otherwise ship the `uv-build` executable alongside the package.
Example fix
# before: build isolation PATH lacks the backend binary
$ pip install ./pkg
RuntimeError: uv-build was not properly installed
# after: make the executable resolvable, then rebuild
$ python -m pip install uv-build
$ python -c "import shutil; print(shutil.which('uv-build'))" # prints a path
$ pip install ./pkg Defensive patterns
Strategy: validation
Validate before calling
import shutil, sysconfig
scripts_dir = sysconfig.get_path("scripts")
expected = "uv" if False else "uv-build" # match USE_UV_EXECUTABLE for your distro
if shutil.which(expected) is None:
raise SystemExit(
f"{expected} not on PATH; install uv/uv-build and add {scripts_dir} to PATH before building"
) Try / catch
# PEP 517 frontend / wrapper around the backend hooks
try:
subprocess.run([sys.executable, "-m", "pip", "wheel", ".", "--no-deps"], check=True)
except subprocess.CalledProcessError as exc:
if "was not properly installed" in (exc.stderr or ""):
# binary missing in build env: install it or disable build isolation
subprocess.run([sys.executable, "-m", "pip", "install", "uv-build"], check=True)
subprocess.run([sys.executable, "-m", "pip", "wheel", ".", "--no-deps", "--no-build-isolation"], check=True)
else:
raise Prevention
- Pin `uv_build` (and uv) in [build-system].requires so build isolation installs a version whose binary ships with the wheel.
- In Docker/CI, run `uv --version` and `python -c "import shutil; print(shutil.which('uv-build'))"` as a smoke test before any build step.
- Prefer `uv build` as the frontend when available; it guarantees the backend binary is reachable.
When it happens
Trigger: Any build of a project with `[build-system] build-backend = "uv_build"` where `shutil.which("uv-build")` (or `shutil.which("uv")` for downstream distributions that flip USE_UV_EXECUTABLE) is None in the build environment: `pip install ./pkg`, `pip wheel`, `python -m build`, `uv build` with build isolation, and the hook then runs in an env whose PATH lacks the directory containing the uv-build script.
Common situations: PATH not including the interpreter's scripts/bin directory inside build isolation; installing with `pip install --target` or `--prefix` so the executable lands outside any PATH dir; a venv created without scripts on PATH; downstream packaging (Debian/Nix) that rebuilt `uv_build` with USE_UV_EXECUTABLE=True but did not ship `uv` on PATH; CI images that sanitize PATH.
Related errors
- Using `uv.{attr_name}` is not allowed; build backend functio
- Could not find the uv binary in any of the following locatio
- Extra names must start and end with a letter or digit and ma
- File not found: `{}`
- Source `{}` does not exist
AI-assisted analysis of astral-sh/uv@f1a42680ff (2026-08-16).
Data as JSON: /api/errors/185af9d958c50650.
Report an issue: GitHub.