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

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

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


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)