pypa/pip · error · InvalidWheelFilename
Invalid wheel filename (wrong number of parts)
Error message
Invalid wheel filename (wrong number of parts): {filename!r} What it means
Raised by parse_wheel_filename() after stripping '.whl', when the remaining stem does not contain exactly 4 or 5 dashes (utils.py:262). A valid wheel stem is {name}-{version}-[{build}-]{pythontag}-{abitag}-{platformtag}: 4 dashes without a build tag, 5 with one. Any other dash count means the filename is structurally malformed.
Solutions
- Ensure the stem follows the pattern {name}-{version}-[{build}-]{pythontag}-{abitag}-{platformtag}.
- Replace hyphens in the project name with underscores when embedding it in a wheel filename.
- Verify all three tag components (python, abi, platform) are present.
Example fix
// before
parse_wheel_filename('foo-1.0-py3-none.whl') // missing platform tag, 3 dashes
// after
parse_wheel_filename('foo-1.0-py3-none-any.whl') Defensive patterns
Strategy: validation
Validate before calling
def safe_parse_wheel(filename: str):
if not filename.endswith(".whl"):
raise ValueError(f"Not a wheel: {filename!r}")
stem = filename[:-4]
if stem.count("-") not in (4, 5):
raise ValueError(f"Wheel stem must have 4 or 5 dashes: {filename!r}")
return parse_wheel_filename(filename) Type guard
def has_valid_wheel_dash_count(filename: str) -> bool:
if not isinstance(filename, str) or not filename.endswith(".whl"):
return False
return filename[:-4].count("-") in (4, 5) Try / catch
from packaging.utils import InvalidWheelFilename
try:
parse_wheel_filename(filename)
except InvalidWheelFilename as e:
if "wrong number of parts" in str(e):
logger.error("Malformed wheel structure: %s", filename)
raise Prevention
- Verify the stem has exactly 4 or 5 dashes before parsing
- Escape dashes in project names as single underscores
- Ensure all three tag components are present
When it happens
Trigger: A wheel filename with a missing tag component (e.g. 'foo-1.0-py3-none.whl' has only 3 dashes), or one with extra unescaped dashes that inflate the part count beyond 5.
Common situations: Manually constructed wheel filenames with formatting errors, a project name containing an unescaped hyphen (should be '_' per PEP 427), or a platform tag that itself contains a dash splitting the count incorrectly.
Related errors
- Invalid build number
- Invalid project name
- Invalid wheel filename (extension must be '.whl')
- 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/644c4d38196042d5.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/utils.py:263
Raises :class:`InvalidWheelFilename` when the version component is invalid.
.. versionadded:: 26.1
The *validate_order* parameter.
.. versionchanged:: 26.3
Raises :class:`InvalidWheelFilename` when an interpreter component is
not an identifier, a tag set component is empty, or the project name is
empty.
"""
if not filename.endswith(".whl"):
raise InvalidWheelFilename(
f"Invalid wheel filename (extension must be '.whl'): {filename!r}"
)
filename = filename[:-4]
dashes = filename.count("-")
if dashes not in (4, 5):
raise InvalidWheelFilename(
f"Invalid wheel filename (wrong number of parts): {filename!r}"
)
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:View on GitHub (pinned to f399c37189)