pypa/pip · error · InvalidWheelFilename
Invalid build number
Error message
Invalid build number: {build_part} in {filename!r} What it means
Raised by parse_wheel_filename() when a build tag is present (5 dashes in the stem) but the build-segment string does not match _build_tag_regex (\d+)(.*) at utils.py:283-287. Per PEP 427, the build tag must start with a digit. If _build_tag_regex.match() returns None, the build number is invalid.
Solutions
- Ensure the build-tag segment starts with one or more digits (e.g. '1', '2final', '100abc').
- Remove the build tag entirely if you do not need one (go back to 4 dashes).
- Move non-numeric build metadata into the version's local segment instead.
Example fix
// before
parse_wheel_filename('foo-1.0-abc-py3-none-any.whl')
// after
parse_wheel_filename('foo-1.0-1abc-py3-none-any.whl') Defensive patterns
Strategy: validation
Validate before calling
import re
_build_tag_regex = re.compile(r"(\d+)(.*)", re.ASCII)
def safe_parse_wheel(filename: str):
stem = filename[:-4]
dashes = stem.count("-")
if dashes == 5:
build_part = stem.split("-", 3)[2]
if _build_tag_regex.match(build_part) is None:
raise ValueError(f"Build tag must start with a digit: {build_part!r}")
return parse_wheel_filename(filename) Type guard
import re
def has_valid_build_tag(filename: str) -> bool:
if not isinstance(filename, str) or not filename.endswith(".whl"):
return False
stem = filename[:-4]
if stem.count("-") != 5:
return True # no build tag present
build_part = stem.split("-", 3)[2]
return bool(re.match(r"\d+", build_part)) Try / catch
from packaging.utils import InvalidWheelFilename
try:
parse_wheel_filename(filename)
except InvalidWheelFilename as e:
if "Invalid build number" in str(e):
logger.error("Wheel build tag must start with a digit: %s", filename)
raise Prevention
- Ensure build-tag segments start with digits (e.g. '1', '2final')
- Omit the build tag entirely (use 4 dashes) if none is needed
- Move non-numeric metadata into the version's local segment
When it happens
Trigger: A wheel filename with 5 dashes where the build segment does not begin with a digit, e.g. 'foo-1.0-abc-py3-none-any.whl' where build part 'abc' fails the regex because it has no leading digit.
Common situations: A build backend that emits a build tag without a numeric prefix, or a manually renamed wheel file where a non-numeric token was placed in the build-tag position.
Related errors
- Invalid project name
- Invalid wheel filename (extension must be '.whl')
- Invalid wheel filename (wrong number of parts)
- Invalid wheel filename (compressed tag set components must…
- Invalid wheel filename (invalid tag component)
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/d332fe76a25b1dee.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/utils.py:285
parts = filename.split("-", dashes - 2)
name_part = parts[0]
# See PEP 427 for the rules on escaping the project name.
if "__" in name_part or _wheel_name_regex.match(name_part) is None:
raise InvalidWheelFilename(f"Invalid project name: {filename!r}")
name = canonicalize_name(name_part)
try:
version = Version(parts[1])
except InvalidVersion as e:
raise InvalidWheelFilename(
f"Invalid wheel filename (invalid version): {filename!r}"
) from e
if dashes == 5:
build_part = parts[2]
build_match = _build_tag_regex.match(build_part)
if build_match is None:
raise InvalidWheelFilename(
f"Invalid build number: {build_part} in {filename!r}"
)
build = cast("BuildTag", (int(build_match.group(1)), build_match.group(2)))
else:
build = ()
tag_str = parts[-1]
try:
tags = parse_tag(tag_str, validate_order=validate_order)
except UnsortedTagsError:
raise InvalidWheelFilename(
f"Invalid wheel filename (compressed tag set components must be in "
f"sorted order per PEP 425): {filename!r}"
) from None
except InvalidTag:
raise InvalidWheelFilename(
f"Invalid wheel filename (invalid tag component): {filename!r}"
) from None
return (name, version, build, tags)View on GitHub (pinned to f399c37189)