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

  1. Ensure the stem follows the pattern {name}-{version}-[{build}-]{pythontag}-{abitag}-{platformtag}.
  2. Replace hyphens in the project name with underscores when embedding it in a wheel filename.
  3. 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

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


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)