pypa/pip · error · InvalidWheelFilename

Invalid wheel filename (extension must be '.whl')

Error message

Invalid wheel filename (extension must be '.whl'): {filename!r}

What it means

Raised by parse_wheel_filename() when the filename does not end with the '.whl' extension. The wheel binary distribution format (PEP 427) mandates the .whl suffix, and this is the very first structural check at utils.py:255. The exception class is InvalidWheelFilename (a ValueError subclass).

Solutions

  1. Ensure the filename ends with '.whl' before calling parse_wheel_filename().
  2. If the file is a source distribution (.tar.gz or .zip), call parse_sdist_filename() instead.
  3. Strip directory components with os.path.basename() if you are passing full paths.

Example fix

// before
name, ver, build, tags = parse_wheel_filename('foo-1.0.tar.gz')
// after
name, ver = parse_sdist_filename('foo-1.0.tar.gz')
Defensive patterns

Strategy: validation

Validate before calling

from packaging.utils import parse_wheel_filename, InvalidWheelFilename

def safe_parse_wheel(filename: str):
    if not filename.endswith(".whl"):
        raise ValueError(f"Not a wheel file: {filename!r}")
    return parse_wheel_filename(filename)

Type guard

def is_wheel_filename(filename: str) -> bool:
    return isinstance(filename, str) and filename.endswith(".whl")

Try / catch

from packaging.utils import InvalidWheelFilename

try:
    name, ver, build, tags = parse_wheel_filename(filename)
except InvalidWheelFilename as e:
    logger.warning("Skipping non-wheel file %s: %s", filename, e)

Prevention

When it happens

Trigger: Calling parse_wheel_filename() with a filename ending in '.tar.gz', '.zip', '.egg', or with no extension at all, e.g. parse_wheel_filename('foo-1.0.tar.gz') or parse_wheel_filename('foo-1.0-py3-none-any').

Common situations: Passing an sdist filename to the wheel parser by mistake, iterating over a mixed directory of wheels and sdists without filtering by extension, or a typo in the filename extension.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/b08b1f0258e7184b. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_vendor/packaging/utils.py:256

    True
    >>> not build
    True

    .. versionadded:: 20.9

    .. versionchanged:: 23.2
       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:

View on GitHub (pinned to f399c37189)