Fix: ERROR: Could not build wheels / Failed building wheel (pip)
Part of: Python Errors
Quick Answer
How to fix pip 'ERROR: Could not build wheels', 'Failed building wheel', 'No matching distribution found', and 'error: subprocess-exited-with-error'. Covers missing C compilers, build tools, system libraries, Python version issues, pre-built wheels, and platform-specific fixes for Linux, macOS, and Windows.
The Error
You run pip install and get one of these:
ERROR: Could not build wheels for numpy, which is required to install pyproject.toml-based projectsFailed building wheel for cryptographyerror: subprocess-exited-with-error
× Building wheel for PyYAML (pyproject.toml) did not run successfully.
│ exit code: 1
╰─> [25 lines of output]
...
error: command 'gcc' failed: No such file or directoryERROR: No matching distribution found for tensorflow==2.15.0These errors all point to the same core problem: pip can’t install a package because it can’t build it from source, can’t find a pre-built binary (wheel) for your platform, or the package doesn’t support your Python version.
Why This Happens
Most Python packages on PyPI are distributed as wheels—pre-built binary packages that install instantly without compilation. But wheels are platform-specific. A wheel built for Linux on x86_64 won’t work on macOS on Apple Silicon.
When pip can’t find a compatible wheel, it falls back to building the package from source. This requires:
- A C/C++ compiler (gcc, clang, or MSVC)
- Python development headers (python3-dev / python3-devel)
- System libraries the package depends on (libffi, libssl, libxml2, etc.)
- Build tools (make, cmake, pkg-config)
If any of these are missing, the build fails. The error messages are often long and buried in compiler output, but the root cause is almost always one of the above.
“No matching distribution found” is different. It means pip can’t find any version of the package (source or wheel) that matches your Python version, OS, or architecture. This typically happens when:
- The package doesn’t support your Python version (e.g., Python 3.13 when the package only supports up to 3.12)
- The package doesn’t have builds for your platform (e.g., ARM64 / Apple Silicon)
- You misspelled the package name
- The package has been removed from PyPI
How Python’s Packaging Stack Changed: PEP 517/518, manylinux, and distutils Removal
The reason this error often spikes after a Python upgrade — even when nothing else on the system changed — is that Python’s packaging stack has moved through several major shifts in the last few years. Knowing which shift you crossed makes the failure obvious.
- PEP 517 / PEP 518 (pyproject.toml-based builds). Before 2017,
python setup.py installwas the canonical build path. PEP 517/518 introducedpyproject.toml-driven builds with isolated build environments. pip 21.3 (October 2021) made PEP 517 the default. The benefit: reproducible builds. The cost: when a build tool (setuptools, hatchling, poetry-core) is missing or pinned wrong, the error message ends up nested two levels deep and looks like a compiler failure when it is actually a build-backend failure. Always read above the “Could not build wheels” line for the real cause. - manylinux tags evolution. Linux wheels carry an ABI tag that says which glibc and which set of system libraries they target.
manylinux1(PEP 513, 2016) — targeted CentOS 5, glibc 2.5. Effectively retired.manylinux2010(PEP 571, 2018) — CentOS 6, glibc 2.12.manylinux2014(PEP 599, 2019) — CentOS 7, glibc 2.17. Still the de facto baseline for older infrastructure.manylinux_2_28(PEP 600, 2019) — based on AlmaLinux 8 / glibc 2.28. Most major projects (NumPy, SciPy, cryptography, lxml) moved here in 2023–2024.manylinux_2_34started appearing in late 2024 for projects that want modern glibc features. If your pip is older than 22.x, it does not understand_2_28or_2_34wheel tags and silently falls back to building from source. Alwayspip install --upgrade pipfirst.
- Python 3.12 removed
distutilsfrom the standard library (PEP 632). Setup scripts that still dofrom distutils.core import setupraiseModuleNotFoundError: No module named 'distutils'. The fix is to migrate the package tosetuptools, or install thesetuptoolscompatibility shim before running the build. Packages last released before 2023 are the usual offenders. - Python 3.13 disabled the GIL as an opt-in build (PEP 703, “free-threaded Python”) in October 2024. Wheels built for the standard 3.13 do not necessarily run on the free-threaded 3.13t. If you installed
python3.13tand a package fails to build, that is the reason — wait for the project to publishcp313twheels. - Rust as a build dependency became mainstream.
cryptography>= 3.4 (March 2021),pydanticv2 core,tokenizers,polars, andruffall need a Rust toolchain to build from source. On Python 3.13 release day in October 2024, none of them had matching wheels for hours — installing on day one required rustc. build-system.requiresis honored from pip 19.0+ only. Very old pip versions ignore the section and try to import setuptools that is not present.
If the error appeared after a Python minor-version upgrade, check whether the wheel tag for your version exists on the PyPI release page before doing anything else.
Fix 1: Install Build Tools and a C Compiler
The most common cause. You’re missing the compiler and development tools needed to build C extensions.
Linux (Debian/Ubuntu)
sudo apt update
sudo apt install build-essential python3-devbuild-essential installs gcc, g++, make, and other essential build tools. python3-dev installs the Python header files needed to compile C extensions.
For a specific Python version:
sudo apt install python3.12-devLinux (Fedora/RHEL/CentOS)
sudo dnf groupinstall "Development Tools"
sudo dnf install python3-develLinux (Arch)
sudo pacman -S base-devel pythonArch ships Python headers with the main python package.
macOS
Install Xcode Command Line Tools:
xcode-select --installThis gives you clang, make, and the standard C headers. You don’t need the full Xcode IDE—the command line tools are sufficient.
If you already have them installed but still get errors after a macOS upgrade, reinstall:
sudo rm -rf /Library/Developer/CommandLineTools
xcode-select --installWindows
Install Microsoft Visual Studio Build Tools:
- Download from https://visualstudio.microsoft.com/visual-cpp-build-tools/
- Run the installer
- Select “Desktop development with C++”
- Install and restart your terminal
Without these build tools, any package with C extensions will fail on Windows. The error usually looks like:
error: Microsoft Visual C++ 14.0 or greater is required.Why this matters: When pip can’t find a pre-built wheel for your platform, it falls back to compiling from source code. This requires a C compiler and system libraries that most developers don’t have installed by default. Installing
build-essentialandpython3-devfixes the vast majority of these failures in one step.
Fix 2: Install Missing System Libraries
Some packages need specific system libraries. The error output usually tells you which one is missing, but it’s buried in the compiler output. Look for lines like fatal error: ffi.h: No such file or directory or Package libssl was not found.
Common packages and their system dependencies
cryptography:
# Debian/Ubuntu
sudo apt install build-essential libssl-dev libffi-dev python3-dev
# Fedora
sudo dnf install openssl-devel libffi-devel python3-devel
# macOS
brew install openssl libffi
export LDFLAGS="-L$(brew --prefix openssl)/lib"
export CPPFLAGS="-I$(brew --prefix openssl)/include"lxml:
# Debian/Ubuntu
sudo apt install libxml2-dev libxslt1-dev python3-dev
# Fedora
sudo dnf install libxml2-devel libxslt-devel python3-devel
# macOS
brew install libxml2 libxsltPillow:
# Debian/Ubuntu
sudo apt install libjpeg-dev zlib1g-dev libfreetype-dev liblcms2-dev libwebp-dev
# Fedora
sudo dnf install libjpeg-devel zlib-devel freetype-devel lcms2-devel libwebp-devel
# macOS
brew install libjpeg zlib freetypepsycopg2:
# Debian/Ubuntu
sudo apt install libpq-dev python3-dev
# Fedora
sudo dnf install postgresql-devel python3-devel
# macOS
brew install postgresqlTip: if a package has a pure-Python or pre-built alternative, use that instead. For example, psycopg2-binary ships pre-built wheels and doesn’t require libpq-dev:
pip install psycopg2-binarymysqlclient:
# Debian/Ubuntu
sudo apt install default-libmysqlclient-dev build-essential python3-dev pkg-config
# Fedora
sudo dnf install mysql-devel python3-devel
# macOS
brew install mysql pkg-configFix 3: Upgrade pip, setuptools, and wheel
An outdated pip may not find wheels that exist on PyPI. Newer pip versions support more wheel formats (including newer manylinux tags) and handle build dependencies better.
python -m pip install --upgrade pip setuptools wheelThen retry your install:
pip install <package>This is especially important on older systems where the default pip might be years old. A pip from 2021 won’t know about manylinux_2_28 wheels published in 2024.
Fix 4: Use Pre-built Wheels (—prefer-binary)
Force pip to prefer pre-built wheels over source distributions:
pip install --prefer-binary <package>This tells pip to choose a wheel even if a newer source distribution is available. Useful when a package has wheels for most versions but the very latest release only has a source dist.
You can also force pip to only install from wheels and never attempt a source build:
pip install --only-binary :all: <package>If no compatible wheel exists, this will fail with an error instead of attempting a doomed build.
Fix 5: Check Python Version Compatibility
The package may not support your Python version. This is the most common cause of “No matching distribution found.”
Check your Python version:
python --versionThen check what Python versions the package supports. Go to the package’s PyPI page (e.g., https://pypi.org/project/<package>/) and look at the “Requires Python” field and the available download files.
You can also check from the command line:
pip install <package>==This intentionally errors but shows all available versions. Pick a version that supports your Python.
If you’re on Python 3.13 and the package only supports up to 3.12, you have two options:
- Wait for the package to release a new version with 3.13 support
- Use an older Python version that the package supports
For managing multiple Python versions, use pyenv (Linux/macOS) or download specific versions from python.org (Windows).
Fix 6: Platform-Specific Wheels (Apple Silicon / ARM64)
If you’re on Apple Silicon (M1/M2/M3/M4) or ARM64 Linux, some packages don’t have pre-built wheels for your architecture.
Apple Silicon (macOS ARM64)
Older packages may only ship x86_64 wheels. Options:
Install Rosetta 2 and use an x86_64 Python:
softwareupdate --install-rosettaThen install the x86_64 version of Python from python.org (the “macOS 64-bit universal2 installer” supports both architectures).
Use Conda/Miniforge: Miniforge provides ARM64-native builds for most scientific Python packages:
# Install Miniforge (ARM64-native)
brew install miniforge
conda create -n myenv python=3.12
conda activate myenv
conda install numpy pandas scipyARM64 Linux (Raspberry Pi, AWS Graviton)
Many packages now have aarch64 wheels, but some still don’t. Install build dependencies and build from source:
sudo apt install build-essential python3-dev gfortran libopenblas-dev
pip install numpyFor scientific packages, Conda (via Miniforge) often has ARM64 builds before PyPI wheels are available.
Pro Tip: Many hard-to-build packages have pre-built alternatives that install instantly. Use
psycopg2-binaryinstead ofpsycopg2,pymysqlinstead ofmysqlclient, andsassinstead ofnode-sass. You avoid the entire build toolchain headache.
Fix 7: Fix Cython / setuptools Version Issues
Some packages require specific versions of Cython or setuptools to build. If you see errors like Cython.Compiler.Errors.CompileError or setuptools.extern.packaging.version.InvalidVersion, try:
pip install --upgrade Cython setuptoolsSome older packages break with newer setuptools. If upgrading doesn’t help, try pinning an older version:
pip install "setuptools<71"
pip install <package>This is common with packages that haven’t updated their build configuration for newer setuptools versions, particularly after setuptools 71.0 removed deprecated features.
Fix 8: Use a Virtual Environment
If you’re installing into the system Python, you might have permission issues or conflicting versions that interfere with the build. A virtual environment gives you a clean slate.
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
pip install --upgrade pip setuptools wheel
pip install <package>This also avoids the externally-managed-environment error on modern Linux distributions.
Still Not Working?
Read the actual error
The pip output is verbose, but the real error is usually near the end. Scroll up past the “ERROR: Could not build wheels” line and look for:
fatal error: *.h: No such file or directory— missing header file. Install the corresponding-dev/-develpackage.command 'gcc' failed— no C compiler installed.pkg-configerrors — installpkg-configand the library it’s looking for.LINK : fatal error LNK*— Windows linker error. Reinstall Visual Studio Build Tools.RuntimeError: CMake must be installed— install cmake:pip install cmakeor use your system package manager.
Install cmake or meson
Some packages (like dlib, llvmlite) need cmake or meson to build:
pip install cmake meson-python meson
# Then retry
pip install <package>Use Conda instead of pip
For scientific and data packages (NumPy, SciPy, TensorFlow, PyTorch, OpenCV), Conda often works when pip doesn’t. Conda ships its own pre-compiled binaries with all dependencies bundled, so you don’t need system libraries.
conda install numpy scipy pandas scikit-learnCheck for a binary variant of the package
Some hard-to-build packages offer a pre-built variant:
| Hard to build | Use this instead |
|---|---|
psycopg2 | psycopg2-binary |
mysqlclient | pymysql (pure Python) |
lxml | pre-built wheels usually available; update pip first |
opencv-python | pre-built on most platforms; check opencv-python-headless |
pillow | pre-built wheels usually available; update pip first |
The package is not on PyPI
“No matching distribution found” can also mean the package name is wrong or it’s hosted elsewhere. Check:
# Verify the package name
pip search <package> # deprecated, use the PyPI website instead
pip install <package> --dry-runSome packages are hosted on custom indexes. Check the project’s documentation for install instructions:
# Example: installing PyTorch from its own index
pip install torch --index-url https://download.pytorch.org/whl/cpuBuild isolation is interfering
pip builds packages in an isolated environment by default (PEP 517). Sometimes this causes issues if the package’s build dependencies have conflicts. Try disabling build isolation:
pip install --no-build-isolation <package>You’ll need to manually install the package’s build dependencies first (check pyproject.toml for [build-system] requires).
You’re behind a proxy or firewall
If pip can’t download build dependencies, the build will fail. Configure pip to use your proxy:
pip install --proxy http://user:[email protected]:8080 <package>Or set the environment variable:
export HTTPS_PROXY=http://proxy.example.com:8080
pip install <package>Rust compiler required
Some packages (like cryptography >= 3.4 and tokenizers) require a Rust compiler. If you see error: can't find Rust compiler:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
pip install <package>On Windows, download and run the Rust installer from https://rustup.rs.
ModuleNotFoundError: No module named 'distutils' on Python 3.12+
If the build log contains this line, the package’s setup.py still imports distutils, which was removed from Python 3.12. Install the compatibility shim:
pip install setuptoolsSetuptools 60+ injects a distutils shim back into sys.modules. If the project’s pyproject.toml does not list setuptools under [build-system] requires, you may also need --no-build-isolation for the install to see it. File an issue with the package upstream — they need to migrate off distutils.
Wheel Cache Has a Bad Build From Last Time
pip caches wheels under ~/.cache/pip/wheels (Linux/macOS) or %LOCALAPPDATA%\pip\Cache (Windows). A previous failed-but-partial build can poison the cache so every subsequent install replays the failure. Clear it:
pip cache purge
pip install --no-cache-dir <package>--no-cache-dir forces a clean download for that single install without affecting future ones.
uv or pip-tools Locked an Old Wheel Tag
If you use uv pip install or pip-tools with a requirements.lock, the lock can pin a wheel from a manylinux generation that no longer exists. Regenerate the lock on the target platform (or use uv lock --upgrade) so the newer manylinux_2_28 tag gets selected. See also Fix: uv not working for related uv troubleshooting.
Related: Fix: ModuleNotFoundError: No module named | Fix: error: externally-managed-environment | Fix: IndentationError: unexpected indent
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: python: command not found (or python3: No such file or directory)
How to fix 'python: command not found', 'python3: command not found', and wrong Python version errors on Linux, macOS, Windows, and Docker. Covers PATH, symlinks, pyenv, update-alternatives, Homebrew, and more.
Fix: pip error: no such option: --break-system-packages
How to fix pip error no such option --break-system-packages caused by old pip versions, PEP 668 externally-managed environments, and virtual environment setup on modern Linux distributions.
Fix: error: externally-managed-environment (pip install)
How to fix the 'error: externally-managed-environment' and 'This environment is externally managed' error when running pip install on Python 3.11+ on Ubuntu, Debian, Fedora, and macOS.
Fix: Electron Forge Not Working — Makers, Code Signing, Native Modules, and Publishers
How to fix Electron Forge errors — forge.config.js makers per OS, code signing on macOS (notarytool) and Windows, native module rebuild via electron-rebuild, Vite/Webpack plugin, auto-updater, and GitHub publisher.