pypa/pip · error · PylockValidationError
At least one hash must be provided
Error message
At least one hash must be provided
What it means
Raised as PylockValidationError by _validate_hashes in packaging.pylock when the 'hashes' table for a sdist/wheel/archive is empty or absent. pylock mandates at least one hash per artifact so integrity can be verified on install.
Source
Thrown at src/pip/_vendor/packaging/pylock.py:263
# for portability
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
return 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 d7d0d0a394)
Solutions
- Populate hashes with at least one strong algorithm: hashes = { sha256 = \"<hex>\" }.
- Regenerate the lockfile with a resolver that records hashes (pip, uv).
- If you control generation, compute sha256 of the artifact and write it.
- Catch the error and re-resolve the offending package.
Example fix
# before
[packages.sdist]
url = \"https://x/pkg-1.0.tar.gz\"
hashes = {}
# after
[packages.sdist]
url = \"https://x/pkg-1.0.tar.gz\"
hashes = { sha256 = \"abc123...\" } Defensive patterns
Strategy: validation
Validate before calling
def has_at_least_one_hash(hashes: dict) -> bool:
return bool(hashes) and len(hashes) >= 1 Type guard
def is_non_empty_hashes(h) -> bool:
return isinstance(h, dict) and len(h) >= 1 Try / catch
try:
PylockFile.from_dict(data)
except PylockValidationError as e:
if 'At least one hash' in str(e):
re_resolve_and_add_hash(e.context) Prevention
- Always compute at least one strong hash (sha256) per artifact.
- Use a resolver that records hashes (pip, uv).
- Validate hashes is non-empty before loading.
- Catch the error and re-resolve the offending package.
When it happens
Trigger: A wheel entry with hashes = {} (empty inline table), or omitting the hashes key when it is required (_get_required_as treats absence as empty). Also an archive table where the resolver failed to populate hashes.
Common situations: Lockfile generated with --no-hashes or by a resolver that does not support hashing; hand-edited entry where hashes were stripped; partial download interrupted before hash computation.
Related errors
- Hash values must be strings
- Algorithm {hash_algorithm!r} used in hash field has differen
- Unexpected type {type(value).__name__} (expected {expected_t
- Unexpected type {type(value).__name__} (expected Sequence)
- Unexpected type {type(item).__name__} (expected {expected_it
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/3e839ec1ef446130.json.
Report an issue: GitHub.