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

  1. 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

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


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)