pypa/pip · error · PylockValidationError
Hash values must be strings
Error message
Hash values must be strings
What it means
Raised by _validate_hashes in pylock.py:274-275. After confirming the hashes mapping is non-empty, every value is checked to be a str; any non-string value (int, bool, float, array) raises PylockValidationError. Hash digests must be string-encoded.
Solutions
- Quote every hash digest so it is a TOML string.
Example fix
# before
hashes = { sha256 = 12345 }
# after
hashes = { sha256 = "12345..." } Defensive patterns
Strategy: type-guard
Validate before calling
def hashes_are_strings(hashes) -> bool:
return all(isinstance(v, str) for v in hashes.values())
Type guard
def hashes_all_str(hashes) -> bool:
return isinstance(hashes, dict) and all(isinstance(v, str) for v in hashes.values())
Try / catch
from packaging.pylock import Pylock, PylockValidationError
try:
Pylock.from_dict(d)
except PylockValidationError as e:
...
Prevention
- Always quote hex digests in TOML.
- Reject numeric/list digests at the hashing boundary.
When it happens
Trigger: In pylock TOML: hashes = { sha256 = 12345 } (int), hashes = { md5 = [1, 2, 3] } (array), hashes = { sha256 = true } (bool).
Common situations: Writing a numeric-looking hex digest as a bare number; a tool emitting binary or list-form digests; forgetting quotes around the hex string.
Related errors
- At least one hash must be provided
- Unexpected type (expected )
- Unexpected type (expected )
- Unexpected type (expected Sequence)
- Cannot determine sdist filename
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/88f9088495d98640.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/pylock.py:275
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):
if cause.context:
self.context = (View on GitHub (pinned to f399c37189)