Troubleshooting¶
This guide helps you resolve common issues when using build.
Build fails with missing dependencies¶
Symptom: Build fails with errors like “ModuleNotFoundError” or “No module named ‘X’”.
Cause: Your build backend or its dependencies aren’t installed in the isolated environment.
Solution 1: Let build handle it automatically (default):
$ python -m build
Build will read your pyproject.toml and install all required dependencies.
Solution 2: If using --no-isolation, manually install dependencies:
$ pip install setuptools your-build-backend
$ python -m build --no-isolation
“Unmet dependencies” with --no-isolation¶
Symptom: A --no-isolation build stops with:
ERROR Unmet dependencies (checked against /usr/local/bin/python3.9):
anndata>=0.7.4
wanted: >=0.7.4
found: not installed
Cause: build checks the declared requirements against the interpreter named in the header (the one running build), not against a virtual environment or your system package manager. Read each entry as:
found: not installed- the package is invisible to that interpreter’s metadata. If you believe it is installed (for example via a Linux distribution or FreeBSD port), it was installed for a different Python, so build cannot see it. Install it for the interpreter in the header, or run that interpreter’spython -m build.found: <version>- the package is installed but its version does not satisfywanted. Upgrade or downgrade it to match.
Solution 1: Install or fix the offending dependency for the interpreter shown in the header.
Solution 2: If you manage build dependencies externally (distribution packaging), skip the check entirely:
$ python -m build --no-isolation --skip-dependency-check
See Basic Usage for more on --skip-dependency-check.
Find the backend version for a bug report¶
Symptom: A backend’s issue tracker asks for the exact version of the backend you used. pyproject.toml lists only
the requirement specifiers (setuptools >= 40.8.0), and on an isolated build the resolved version lives in the
temporary environment that build deletes afterwards.
Solution: Read it from build’s output. After installing the build dependencies, build prints the resolved version of each one:
$ python -m build --wheel
...
* Getting build dependencies for wheel...
* Installed build dependency versions:
- setuptools==82.0.1
* Building wheel...
Copy the name==version line for the backend into your report. With --no-isolation build installs nothing, so
read the version from the active interpreter instead (for example pip show setuptools).
Build hangs or appears frozen¶
Symptom: Build command runs but produces no output for a long time.
Possible causes:
Waiting for authentication: If you’re using a private package index, build may be waiting for credentials.
See Corporate Environments for authentication setup.
Large download: Build backend dependencies are being downloaded.
Use
-vor-vvfor verbose output:$ python -m build -vv
Build backend is actually running: Some backends (especially for C extensions) can take time.
Check system monitor for CPU/disk activity to confirm work is happening.
SSL certificate verification failed¶
Symptom: Errors like “SSL: CERTIFICATE_VERIFY_FAILED” or “certificate verify failed”.
Cause: Your system doesn’t trust the SSL certificate of the package index.
Solution 1: Provide the CA certificate (recommended):
$ export PIP_CERT=/path/to/company-ca-bundle.crt
$ python -m build
Solution 2: Use build with virtualenv for better SSL support:
$ pip install build[virtualenv]
$ python -m build
Solution 3: For development only, disable verification (not recommended):
$ export PIP_TRUSTED_HOST=pypi.company.com
$ python -m build
See Corporate Environments for more details.
Permission denied errors¶
Symptom: “PermissionError” or “Access is denied” when creating directories or files.
Common causes:
Output directory is protected: The
dist/directory is owned by another user or process.Solution: Remove the directory first or use a different output location:
$ rm -rf dist/ $ python -m build
Or:
$ python -m build --outdir /tmp/my-build
Running inside a read-only directory: The source directory is on a read-only filesystem.
Solution: Copy the source to a writable location first.
Antivirus software: Some antivirus tools block Python from creating virtual environments.
Solution: Add Python and your project directory to antivirus exclusions.
Wheel is not compatible with this platform¶
Symptom: “is not a supported wheel on this platform” when trying to install the built wheel.
Cause: The wheel was built for a different Python version or platform.
Solution: Build on the same platform and Python version where you’ll install, or use cibuildwheel for multi-platform builds.
See build vs Other Tools for when to use cibuildwheel vs build.
Build succeeds but package is missing files¶
Symptom: After building, the package installs but is missing source files, data files, or modules.
Cause: Files aren’t included in the source distribution manifest.
Solution: The fix depends on your build backend:
For setuptools (setuptools documentation):
Add a MANIFEST.in file or use package_data in pyproject.toml:
[tool.setuptools.package-data]
mypackage = ["data/*.json", "templates/*.html"]
For hatchling (hatchling documentation):
Use the include and exclude options:
[tool.hatch.build.targets.wheel]
include = [
"src/**/*.py",
"src/**/*.json",
]
For flit (flit documentation):
Flit includes all files tracked by git by default. Ensure files are committed.
Test your sdist: Always verify the sdist contains all necessary files:
$ python -m build --sdist
$ tar -tzf dist/mypackage-1.0.0.tar.gz
ModuleNotFoundError in the built wheel¶
Symptom: The wheel installs successfully, but importing the package fails with “ModuleNotFoundError”.
Cause: The package structure in your source doesn’t match what the build backend expects.
Common issues:
Missing ``__init__.py``: Ensure every package directory has an
__init__.pyfile (not needed for namespace packages).Wrong directory structure: For src-layout, ensure you have
src/packagename/not justpackagename/.Not configuring package discovery: Tell your build backend where to find packages.
For setuptools with src-layout:
[tool.setuptools.packages.find] where = ["src"]
Version conflict between build dependencies¶
Symptom: Build fails with errors about conflicting package versions.
Cause: Build dependencies have incompatible version requirements.
Solution 1: Update your build backend and its dependencies:
$ pip install --upgrade pip setuptools
Then try building again:
$ python -m build
Solution 2: If using --no-isolation, create a fresh virtual environment:
$ python -m venv fresh-env
$ source fresh-env/bin/activate # On Windows: fresh-env\\Scripts\\activate
$ pip install build
$ python -m build
The isolated build (without --no-isolation) avoids this issue by creating a clean environment each time.
Build works locally but fails in CI¶
Common causes:
Different Python versions: CI may use a different Python version than your local environment.
Solution: Specify Python version in CI config, test locally with that version.
Missing system dependencies: C extensions may need system libraries.
Solution: Install required libraries in CI before building:
# GitHub Actions example - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y libffi-dev
File path issues: Windows vs Unix path separators.
Solution: Use
pathlib.Pathinpyproject.tomlconfigurations and build scripts.Git not available: Some backends use git for version detection.
Solution: Ensure git is installed in CI, or use explicit versioning in
pyproject.toml.
See CI/CD Integration for CI-specific guidance.
Catching deprecation warnings¶
To catch warnings from your build backend in CI:
$ PYTHONWARNINGS=error::DeprecationWarning python -m build
Or for setuptools specifically:
$ PYTHONWARNINGS=error:::setuptools.config.setupcfg python -m build
This fails the build if deprecated features are used, helping you catch issues early.
Build backend not found¶
Symptom: “Backend ‘X’ is not available” or “No module named ‘X’”.
Cause: The build backend specified in pyproject.toml isn’t installed.
Solution: This shouldn’t happen with isolated builds (the default). If you see this:
Check your
pyproject.toml[build-system]section is correct:[build-system] requires = ["hatchling"] build-backend = "hatchling.build"
If using
--no-isolation, install the backend:$ pip install hatchling $ python -m build --no-isolation
No build-system section in pyproject.toml¶
Symptom: Build succeeds but you’re not sure which backend is being used.
Cause: No [build-system] section is specified in pyproject.toml.
Solution: As recommended in PEP 517, if no backend is specified, build will fallback to
setuptools.build_meta:__legacy__. This is for backward compatibility with older projects. For new projects,
explicitly specify your build backend:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
This makes your build configuration explicit and avoids relying on the fallback behavior.
Build installed in user site-packages¶
Symptom: Virtual environment creation fails with errors like “executable /usr/local/bin/python missing”.
Cause: When build is installed in the user site-packages (pip install --user build), it can interfere with
isolated environment creation.
Solution: Install build in a virtual environment instead:
$ python -m venv build-env
$ source build-env/bin/activate # On Windows: build-env\\Scripts\\activate
$ pip install build
$ python -m build
Or use pipx to install build in isolation:
$ pipx install build
$ pipx run build
Package name has dashes but wheel has underscores¶
Symptom: Your package is named my-package but the wheel is my_package-1.0.0-py3-none-any.whl.
This is expected behavior: According to PEP 427, wheel filenames normalize package names by replacing dashes with underscores. This is not a bug.
Your users can still install with either name:
$ pip install my-package # Works
$ pip install my_package # Also works
The package metadata preserves your original name, only the filename is normalized.
Getting more information¶
Verbose output¶
Use -v or -vv for detailed output:
$ python -m build -v # Verbose
$ python -m build -vv # Very verbose
This shows what build is doing and can help identify where failures occur.
Check your configuration¶
Verify your pyproject.toml is valid:
$ python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb')))"
Test the build backend directly¶
You can test if your build backend works independently:
$ pip install your-build-backend
$ python -m your_build_backend
Inspect the build environment¶
build removes its isolated environment when the build ends. To keep it for inspection, point --env-dir at an empty
location:
$ python -m build --env-dir .build-env
build removes that location after a successful build and keeps it after a failure, so a failed build leaves the
environment in .build-env for you to examine. Setting TMPDIR (or TEMP on Windows) only moves the temporary
directory; it does not keep the environment around.
build forwards the backend’s output to your terminal as it happens, so compilation logs and error messages are already visible. Raise the verbosity to add build’s own diagnostics and stream the environment setup live:
$ python -m build -vv
Debug a failed build¶
When a backend fails, build prints a TIP line that links back here. Work through these steps to gather what you
need.
Stream the backend output¶
build forwards everything the backend writes to standard output and error straight to your terminal, so compiler invocations and backend tracebacks already appear without any extra flag. Raise the verbosity to add build’s own diagnostics and to stream the environment setup (installing the backend and its dependencies) live instead of only on failure:
$ python -m build -vv
Keep the build environment and sources¶
A failed build deletes its temporary working directories before you can look at them. Pin both so they survive the run:
$ python -m build --env-dir .build-env --sdist-extract-dir .build-src
--env-dir keeps the isolated environment (the installed backend and its dependencies) on failure; see Inspect the
build environment. --sdist-extract-dir keeps the extracted sdist, which is the directory the backend actually runs
in, so any files the backend leaves next to your sources stay put.
Find the backend’s own logs¶
build cannot capture log files the backend writes inside its own working directory, because PEP 517 gives the frontend
no way to discover them. Each backend exposes its own setting for keeping them. For meson-python and
scikit-build, point its build directory at a path you control:
$ python -m build -C build-dir=_build
The backend then usually writes its build tree and logs under _build. Check your backend’s documentation for the
equivalent setting.
Still having issues?¶
If your issue isn’t covered here:
Check the issue tracker for similar problems
Enable verbose output (
-vv) and include the full output when reporting issuesInclude your
pyproject.tomland Python version when asking for help
See also¶
Corporate Environments for proxy, SSL, and authentication issues
CI/CD Integration for CI/CD-specific problems
Environment Variables for environment variables that affect build