This error nearly always means one thing: there is no prebuilt wheel for the package on your Python version and platform, so pip fell back to building from source, and the source build failed. The message after error: subprocess-exited-with-error is the real error. The wheel line is just where pip gave up.
It reads like a pip bug, and pip even tells you it probably is not one. It is right. In the overwhelming majority of cases the cause is a version mismatch between a package and your Python interpreter, and the fix is either an older package, a newer package, or a different Python — not a pip flag.
Table of contents
- Reading the error properly
- The most common cause: your Python is too new
- When the package is too old for your Python
- Fixing missing build tools
- The flags that help and the ones that do not
- Why this bites hardest in CI and containers
- How this fits the rest of the stack
- FAQ
Reading the error properly
The output is long and the useful part is not the part that looks important.
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> [33 lines of output]
...
RuntimeError: Cannot install on Python version 3.13.1; only
versions >=3.8,<3.13 are supported.
[end of output]
note: This error originates from a subprocess, and is likely
not a problem with pip.
Read the lines between [N lines of output] and [end of output]. That block is stdout and stderr from the package’s own build system. The banner around it is pip reporting that someone else’s process failed.
The three messages that account for most cases:
Cannot install on Python version 3.X— explicit version guard. Straightforward.error: Microsoft Visual C++ 14.0 or greater is required— Windows, no compiler, source build.fatal error: Python.h: No such file or directory— Linux, missing Python development headers.
Each of those has a different fix, which is why the first move is reading rather than trying flags.
The most common cause: your Python is too new
Wheels are compiled per Python version. When 3.13 ships, every package with C extensions needs a new release built against it. Maintainers do that on their own schedule, and popular scientific packages often lag by months.
So installing on a brand-new Python is the reliable way to hit this. Check what you are on and what the package supports:
python --version
# What versions of this package exist, and which does pip see?
pip index versions pillow
# Show the wheels available for your exact interpreter
pip download pillow --no-deps -d /tmp/whl && ls /tmp/whl
If pip download produces a .tar.gz rather than a .whl, there is no binary for your platform and every install will attempt a source build.
The fix is usually to move Python, not the package. Running one minor version behind the newest release is the pragmatic default for anything with C dependencies.
# With pyenv
pyenv install 3.12.8
pyenv local 3.12.8
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# With uv, which resolves and creates the environment in one step
uv venv --python 3.12
uv pip install -r requirements.txt
When the package is too old for your Python
The mirror image, and more common in older projects: a pinned requirement from 2022 that predates your interpreter entirely.
A requirements.txt pinning numpy==1.21.0 will never install on Python 3.12, because no such wheel exists and the source will not compile. No amount of build tooling fixes this — the package simply predates the interpreter.
# Which pin is the problem? Install one at a time to find out.
pip install -r requirements.txt 2>&1 | grep -E 'error|Building wheel'
# Relax the pin to a compatible range
pip install 'numpy>=1.26'
# Then regenerate the lock from what actually resolved
pip freeze > requirements.txt
This is the strongest argument for keeping dependencies moving. A project pinned exactly and never updated becomes uninstallable, and the cost of unsticking it grows every year.
Fixing missing build tools
If the package genuinely needs compiling and you want to compile it, install the toolchain. Platform-specific and mechanical.
# Debian / Ubuntu
sudo apt-get update
sudo apt-get install -y build-essential python3-dev
# Common extras, depending on what the package links against
sudo apt-get install -y libpq-dev libssl-dev libffi-dev libjpeg-dev zlib1g-dev
# Fedora / RHEL
sudo dnf install -y gcc gcc-c++ python3-devel
# macOS
xcode-select --install
On Windows the answer is the Microsoft C++ Build Tools, selecting the Desktop development with C++ workload. It is a large download and it is the only real fix for that message.
Before installing a compiler, check whether you need to. Many packages ship pure-Python fallbacks or have a binary-only distribution under a different name — psycopg2-binary instead of psycopg2 is the classic example, and it removes the libpq-dev requirement entirely.
The flags that help and the ones that do not
A few pip options are genuinely useful here. Several widely-recommended ones are not.
# Useful: see the full build output instead of a truncated block
pip install -v package-name
# Useful: skip the build isolation env when it is the thing failing
pip install --no-build-isolation package-name
# Useful: refuse source builds, so you fail fast with a clear message
pip install --only-binary :all: package-name
# Useful: an old pip may not understand a modern package's metadata
python -m pip install --upgrade pip setuptools wheel
--only-binary :all: deserves particular attention. It converts a confusing ten-minute compile failure into an immediate no matching distribution message, which tells you the truth faster.
What does not help: --no-cache-dir (the cache is not the problem), --force-reinstall (same failure, more slowly), and sudo pip install (adds a permissions problem on top of the build problem).
Why this bites hardest in CI and containers
The build that works locally and fails in the pipeline is usually a base-image difference. Your laptop has a compiler and years of accumulated headers. A slim container image has neither.
python:3.12-slim omits build-essential deliberately, so any package without a wheel fails there and only there.
FROM python:3.12-slim
# Build deps installed, used, and removed in one layer
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential python3-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt \
&& apt-get purge -y build-essential python3-dev \
&& apt-get autoremove -y
COPY . /app
WORKDIR /app
Better still, avoid needing the compiler: pin to versions with wheels for your Python, prefer -binary package variants, and add --only-binary :all: in CI so a source build fails loudly at review time rather than silently adding four minutes to every deploy.
On RunxBuild, Python services build from the repository and surface the full build log, so a wheel failure shows the same output block you would see locally rather than a generic build-failed status. The Python services documentation covers how the build stage reads your requirements file.
How this fits the rest of the stack
The message is a wrapper, not a diagnosis. Read the subprocess output, check your Python version against the package’s supported range, and reach for a different interpreter or a different pin before installing a compiler. Pinning to wheel-available versions keeps the whole class of problem out of your pipeline. If you are sizing a Python service and want the build minutes and runtime as separate figures, the RunxBuild hosting calculator lays them out.
Useful related references:
- WordPress 6.9 Broke My Site: Getting Back Up Before Debugging
- VPS SSD Storage: What You’re Actually Getting, When It Matters, When It Doesn’t
- Java Object Cache: Picking One and Not Getting Burned by It
- Builds on RunxBuild
FAQ
What does getting requirements to build wheel did not run successfully mean?
It means pip could not find a prebuilt wheel for your Python version and platform, so it tried to build the package from source and that build failed. The real error is in the output block between the bracketed line counts, not in the wheel message itself.
How do I fix this error?
Read the subprocess output first. If it names a Python version, switch interpreters — usually to one minor version behind the newest. If it names a missing compiler or Python.h, install build-essential and python3-dev. If the package is old and pinned, relax the pin.
Why does it work on my machine but fail in Docker?
Slim base images like python:3.12-slim omit compilers and development headers on purpose. Your local machine has them. Either install build-essential in the image or pin to versions that ship wheels.
Does upgrading pip fix this?
Sometimes. An older pip may not understand a newer package’s build metadata. Run python -m pip install —upgrade pip setuptools wheel as a cheap first attempt, but it will not help when the underlying cause is a version mismatch.
How do I fail fast instead of waiting for a compile?
Add —only-binary :all: to the install. Pip then refuses source builds and reports no matching distribution immediately, which identifies the real problem far faster than a ten-minute failed compile.