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
- Open pylock.toml and locate the wheel entry named in the error's context (e.g. wheels[2]); read its filename field.
- Rewrite the filename to the canonical wheel pattern name-version-{pythontag}-{abitag}-{platformtag}.whl, e.g. 'requests-2.31.0-py3-none-any.whl'.
- If unsure of the exact tag segments, regenerate the lock file with the original lock-producing tool rather than editing by hand.
- 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
- Always obtain pylock.toml from a trusted locker rather than editing filenames by hand.
- Run Pylock.validate() right after loading and surface the context field to localize the bad entry.
- Add a pre-commit check that calls parse_wheel_filename on every wheel filename in the lock.
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
- Cannot determine wheel filename
- Invalid sdist filename
- Name in is not consistent with package name
- Version in is not consistent with package version
- Cannot determine sdist filename
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)