pypa/pip · error · PylockValidationError

Hash values must be strings

Error message

Hash values must be strings

What it means

Raised as PylockValidationError by _validate_hashes in packaging.pylock when the hashes table is non-empty but at least one value is not a string. pylock requires every hash value to be a hex digest string; an int, list, or inline table value is rejected.

Source

Thrown at src/pip/_vendor/packaging/pylock.py:265

        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):
            if cause.context:
                self.context = (

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Ensure each hash value is a hex string, e.g. hashes = { sha256 = \"abcdef...\" }.
  2. Regenerate the lockfile with a resolver that writes hex digests.
  3. If generating programmatically, call hashlib.sha256(data).hexdigest().
  4. Validate the hashes mapping types before calling from_dict.

Example fix

# before
hashes = { sha256 = 123 }
# after
hashes = { sha256 = \"e3b0c44298fc1c149afbf4c8996fb924...\" }
Defensive patterns

Strategy: type-guard

Validate before calling

def hashes_are_strings(h: dict) -> bool:
    return all(isinstance(v, str) for v in h.values())

Type guard

from typing import Mapping

def is_string_valued_hashes(h: Mapping) -> bool:
    return all(isinstance(v, str) for v in h.values())

Try / catch

try:
    PylockFile.from_dict(data)
except PylockValidationError as e:
    if 'Hash values must be strings' in str(e):
        coerce_hash_values_to_hex_strings(e.context)

Prevention

When it happens

Trigger: hashes = { sha256 = 12345 } (int), hashes = { sha256 = [\"a\", \"b\"] } (list), or hashes = { sha256 = { digest = \"...\" } } (table). The error fires after the 'at least one hash' check has passed.

Common situations: Tooling that emits hash byte-length instead of the digest; a TOML converter that quoted only keys; copy-pasting a hash object instead of its hex attribute.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/88f9088495d98640.json. Report an issue: GitHub.