astral-sh/ruff · error · RuffNotFound

Could not find the ruff binary in any of the following locat

Error message

Could not find the ruff binary in any of the following locations:
{locations}

What it means

The ruff PyPI package is a thin Python wrapper around a prebuilt Rust executable. find_ruff_bin() in python/ruff/_find_ruff.py probes a fixed list of locations (the current Python's scripts dir, the base-prefix scripts dir, the bin directory above the site-packages/ruff package for --prefix and `uv run --with` installs, the bin dir adjacent to the package for pip install --target, and the user scheme scripts dir such as ~/.local/bin) for ruff(.exe). RuffNotFound is raised only when every candidate directory has been checked and none contains the binary; the message lists each location that was actually searched.

Source

Thrown at python/ruff/_find_ruff.py:53

        # with module path `<target>/ruff`
        _join(_matching_parents(_module_path(), "ruff"), "bin"),
        # The user scheme scripts directory, e.g., `~/.local/bin`
        sysconfig.get_path("scripts", scheme=_user_scheme()),
    ]

    seen = []
    for target in targets:
        if not target:
            continue
        if target in seen:
            continue
        seen.append(target)
        path = os.path.join(target, ruff_exe)
        if os.path.isfile(path):
            return path

    locations = "\n".join(f" - {target}" for target in seen)
    raise RuffNotFound(
        f"Could not find the ruff binary in any of the following locations:\n{locations}\n"
    )


def _module_path() -> str | None:
    path = os.path.dirname(__file__)
    return path


def _matching_parents(path: str | None, match: str) -> str | None:
    """
    Return the parent directory of `path` after trimming a `match` from the end.
    The match is expected to contain `/` as a path separator, while the `path`
    is expected to use the platform's path separator (e.g., `os.sep`). The path
    components are compared case-insensitively and a `*` wildcard can be used
    in the `match`.
    """
    from fnmatch import fnmatch

View on GitHub (pinned to d1087a4b9e)

Solutions

  1. Force-reinstall from a prebuilt wheel: pip install --force-reinstall --only-binary :all: ruff (or uv pip install --reinstall ruff).
  2. Verify a wheel exists for your platform on PyPI; if not, switch base image/platform (e.g. manylinux instead of musl) or build the binary with cargo and put it on PATH.
  3. If the binary exists elsewhere (vendored or moved), copy ruff(.exe) into one of the directories listed in the error message (e.g. the scripts dir or the bin directory next to the package).
  4. Bypass the wrapper entirely and run the binary via uvx ruff or the standalone installer.

Example fix

# before: source install without a platform wheel
pip install ruff --no-binary ruff
python -m ruff --version   # RuffNotFound: binary missing from every searched location

# after: install the platform wheel that bundles the executable
pip install --only-binary :all: --force-reinstall ruff
python -m ruff --version   # ruff x.y.z
Defensive patterns

Strategy: try-catch

Validate before calling

import sysconfig
from pathlib import Path


def ruff_binary_available() -> bool:
    try:
        import ruff  # noqa: F401
    except ImportError:
        return False
    exe = 'ruff' + (sysconfig.get_config_var('EXE') or '')
    pkg_dir = Path(ruff.__file__).parent
    candidates = [
        sysconfig.get_path('scripts'),
        sysconfig.get_path('scripts', vars={'base': sys.base_prefix}),
        str(pkg_dir.parent / 'bin'),
    ]
    return any(p and Path(p, exe).is_file() for p in candidates)

Try / catch

from ruff._find_ruff import RuffNotFound, find_ruff_bin
import shutil

try:
    ruff_bin = find_ruff_bin()
except RuffNotFound:
    ruff_bin = shutil.which('ruff')  # fall back to a binary on PATH
    if ruff_bin is None:
        raise

Prevention

When it happens

Trigger: Calling find_ruff_bin() (directly, or indirectly via `python -m ruff` or the generated Python API) when the ruff executable is absent from all probed directories: an sdist/source install that never shipped a binary, a wheel for a platform without prebuilt artifacts, a container image whose cleanup step deleted compiled files, or a pip install --target/--prefix layout where the sibling bin directory was not created.

Common situations: Docker multi-stage builds that strip site-packages; musl-based or exotic-architecture images where pip builds from source without placing the binary; mixing conda and pip environments; vendoring the ruff package without its bin directory; CI caching a broken wheel.

Related errors


AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20). Data as JSON: /api/errors/295545d13a89c81c. Report an issue: GitHub.