pypa/pip · error · PylockValidationError

Invalid wheel filename

Error message

Invalid wheel filename {wheel.filename!r}

What it means

A PylockValidationError raised during Package validation (Pylock.from_dict / Pylock.validate) when parse_wheel_filename cannot parse a [[packages.wheels]].filename. PEP 751 (pylock.toml) requires every wheel filename to follow the canonical 'name-version-pythontag-abitag-platformtag.whl' shape, so a structurally malformed string is rejected before any selection happens.

Solutions

  1. Open pylock.toml and locate the wheel entry named in the error's context (e.g. wheels[2]); read its filename field.
  2. Rewrite the filename to the canonical wheel pattern name-version-{pythontag}-{abitag}-{platformtag}.whl, e.g. 'requests-2.31.0-py3-none-any.whl'.
  3. If unsure of the exact tag segments, regenerate the lock file with the original lock-producing tool rather than editing by hand.
  4. Re-run Pylock.from_dict / Pylock.validate to confirm the error is gone before calling select().

Example fix

# before
[[packages]]
name = "requests"
version = "2.31.0"
  [[packages.wheels]]
  filename = "requests-2.31.0.whl"

# after
[[packages]]
name = "requests"
version = "2.31.0"
  [[packages.wheels]]
  filename = "requests-2.31.0-py3-none-any.whl"
Defensive patterns

Strategy: validation

Validate before calling

from packaging.utils import parse_wheel_filename

def is_valid_wheel_filename(filename: str) -> bool:
    try:
        parse_wheel_filename(filename)
        return True
    except Exception:
        return False

# before Pylock.from_dict, scrub every wheel filename:
for p in toml_dict.get('packages', []):
    for w in p.get('wheels', []) or []:
        if not is_valid_wheel_filename(w['filename']):
            raise ValueError(f"bad wheel filename: {w['filename']!r}")

Type guard

null

Try / catch

from packaging.pylock import Pylock, PylockValidationError
try:
    pylock = Pylock.from_dict(toml_dict)
except PylockValidationError as e:
    # e.context like 'packages[2].wheels[1]'; e.message is the human text
    log.error("lock validation failed at %s: %s", e.context, e.message)
    raise

Prevention

When it happens

Trigger: Calling Pylock.from_dict(toml_dict) or Pylock.validate() on a lock whose [[packages.wheels]] entry has a filename like 'foo.whl' (missing version/tag segments), 'foo-1.0.tar.gz' (sdist extension on a wheel entry), or 'Foo--py3-none-any.whl' (empty version). The context field is 'wheels[i]' pointing at the offending entry index.

Common situations: Hand-edited pylock.toml, lock files emitted by an experimental/buggy lock generator, wheels renamed post-build (losing the canonical dash structure), or a wheel filename copied from a URL that included a trailing query/hash.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/packaging/pylock.py:617

        )
        distributions = bool(package.sdist) + len(package.wheels or [])
        direct_urls = (
            bool(package.vcs) + bool(package.directory) + bool(package.archive)
        )
        if distributions > 0 and direct_urls > 0:
            raise PylockValidationError(
                "None of vcs, directory, archive must be set if sdist or wheels are set"
            )
        if distributions == 0 and direct_urls != 1:
            raise PylockValidationError(
                "Exactly one of vcs, directory, archive must be set "
                "if sdist and wheels are not set"
            )
        for i, wheel in enumerate(package.wheels or []):
            try:
                (name, version, _, _) = parse_wheel_filename(wheel.filename)
            except Exception as e:
                raise PylockValidationError(
                    f"Invalid wheel filename {wheel.filename!r}",
                    context=f"wheels[{i}]",
                ) from e
            if name != package.name:
                raise PylockValidationError(
                    f"Name in {wheel.filename!r} is not consistent with "
                    f"package name {package.name!r}",
                    context=f"wheels[{i}]",
                )
            if package.version and version != package.version:
                raise PylockValidationError(
                    f"Version in {wheel.filename!r} is not consistent with "
                    f"package version {str(package.version)!r}",
                    context=f"wheels[{i}]",
                )
        if package.sdist:
            try:
                name, version = parse_sdist_filename(package.sdist.filename)

View on GitHub (pinned to f399c37189)