pypa/pip · error · PylockValidationError
Cannot determine wheel filename
Error message
Cannot determine wheel filename
What it means
Raised as PylockValidationError by PackageWheel.filename (a computed property) in packaging.pylock when none of name, path, or url is set on a wheel entry, so the wheel filename cannot be derived. The filename is required by parse_wheel_filename for the wheel-name/version consistency checks in Package._from_dict.
Source
Thrown at src/pip/_vendor/packaging/pylock.py:515
@classmethod
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
package_wheel = cls(
name=_get(d, str, "name"),
upload_time=_get(d, datetime, "upload-time"),
url=_get(d, str, "url"),
path=_get(d, str, "path"),
size=_get(d, int, "size"),
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
)
_validate_path_url(package_wheel.path, package_wheel.url)
return package_wheel
@property
def filename(self) -> str:
"""Get the filename of the wheel."""
filename = self.name or _path_name(self.path) or _url_name(self.url)
if not filename:
raise PylockValidationError("Cannot determine wheel filename")
return filename
@dataclass(frozen=True, init=False)
class Package:
name: NormalizedName
version: Version | None = None
marker: Marker | None = None
requires_python: SpecifierSet | None = None
dependencies: Sequence[Mapping[str, Any]] | None = None
vcs: PackageVcs | None = None
directory: PackageDirectory | None = None
archive: PackageArchive | None = None
index: str | None = None
sdist: PackageSdist | None = None
wheels: Sequence[PackageWheel] | None = None
attestation_identities: Sequence[Mapping[str, Any]] | None = None
tool: Mapping[str, Any] | None = NoneView on GitHub (pinned to d7d0d0a394)
Solutions
- Provide name (e.g. 'pkg-1.0-py3-none-any.whl'), path, or url on each wheel entry.
- Regenerate the lockfile so every wheel records its filename or URL.
- Validate wheels before adding them to the package.
- Catch the error and report which wheel index is malformed (context).
Example fix
# before
[[packages.wheels]]
hashes = { sha256 = \"...\" }
# after
[[packages.wheels]]
name = \"pkg-1.0-py3-none-any.whl\"
hashes = { sha256 = \"...\" } Defensive patterns
Strategy: validation
Validate before calling
def wheel_has_filename(w: dict) -> bool:
return bool(w.get('name') or w.get('path') or w.get('url')) Type guard
def is_named_wheel(d) -> bool:
return bool(d.get('name') or d.get('path') or d.get('url')) Try / catch
try:
_ = wheel.filename
except PylockValidationError as e:
if 'Cannot determine wheel filename' in str(e):
w['name'] = f'{pkg.name}-{pkg.version}-py3-none-any.whl' Prevention
- Provide name (full wheel filename) or path/url on each wheel.
- Use a resolver to populate wheel filenames.
- Validate each wheel entry has a locator.
- Catch the error and report the wheel index (context).
When it happens
Trigger: A [[packages.wheels]] table with neither name, path, nor url; or a PackageWheel(...) constructed in code without any locator. Accessing .filename (often indirectly via the wheel validation loop at line ~597) triggers it.
Common situations: Lockfile with a wheel entry missing its locator fields; resolver that wrote the wheel hash but not the filename/URL; hand-editing that deleted the URL.
Related errors
- Invalid wheel filename {wheel.filename!r}
- Name in {wheel.filename!r} is not consistent with package na
- path or url must be provided
- Cannot determine sdist filename
- None of vcs, directory, archive must be set if sdist or whee
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/e7523a644702c49d.json.
Report an issue: GitHub.