pypa/pip · error · PylockValidationError
At least one hash must be provided
Error message
At least one hash must be provided
What it means
Raised by _validate_hashes in pylock.py:271-273, which is applied to the 'hashes' table of every PackageSdist, PackageWheel and PackageArchive. The hashes mapping must contain at least one algorithm->digest entry; an empty (or effectively empty) hashes table raises PylockValidationError. (A completely missing hashes key is a separate 'Missing required value' error from _get_required_as.)
Solutions
- Populate at least one hash entry, conventionally sha256, e.g. hashes = { sha256 = "<hex>" }.
Example fix
# before
[[packages.sdist]]
name = "x-1.0.tar.gz"
hashes = {}
# after
[[packages.sdist]]
name = "x-1.0.tar.gz"
hashes = { sha256 = "abcdef..." } Defensive patterns
Strategy: validation
Validate before calling
def has_at_least_one_hash(hashes) -> bool:
return bool(hashes) and len(hashes) >= 1
Try / catch
from packaging.pylock import Pylock, PylockValidationError
try:
Pylock.from_dict(d)
except PylockValidationError as e:
...
Prevention
- Compute and record at least one digest (sha256) for every artifact before emitting the lock file.
- Treat an empty hashes table as a build error, not a placeholder.
When it happens
Trigger: In pylock TOML: [[packages.sdist]] with hashes = {}, or a wheel/archive entry whose hashes table is empty.
Common situations: Generating a lock file before computing integrity hashes; using an empty placeholder hashes table during development.
Related errors
- Hash values must be strings
- Cannot determine sdist filename
- Cannot determine wheel filename
- Cannot select requirements from pylock file
- Directory entries are not supported in remote pylock.toml
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/3e839ec1ef446130.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/pylock.py:273
if "/" in path:
return path.rsplit("/", 1)[-1]
elif "\\" in path:
return path.rsplit("\\", 1)[-1]
else:
return path
def _url_name(url: str | None) -> str | None:
if not url:
return None
url_path = urlparse(url).path
# The last path component is percent-encoded, so decode it to the file name
return unquote(url_path.rsplit("/", 1)[-1])
def _validate_hashes(hashes: Mapping[str, Any]) -> Mapping[str, Any]:
if not hashes:
raise PylockValidationError("At least one hash must be provided")
if not all(isinstance(hash_val, str) for hash_val in hashes.values()):
raise PylockValidationError("Hash values must be strings")
return hashes
class PylockValidationError(Exception):
"""Raised when when input data is not spec-compliant."""
context: str | None = None
message: str
def __init__(
self,
cause: str | Exception,
*,
context: str | None = None,
) -> None:
if isinstance(cause, PylockValidationError):View on GitHub (pinned to f399c37189)