pypa/pip · error · DirectUrlValidationError
Algorithm used in hash field has different value in hashes…
Error message
Algorithm {hash_algorithm!r} used in hash field has different value in hashes field What it means
When both the legacy hash field and the hashes mapping exist and the algorithm from hash is present in hashes, the digest values must match exactly. If they differ, DirectUrlValidationError is raised, indicating a hash conflict that could signal tampering or corruption.
Solutions
- Recompute the correct hash from the actual file and update both fields (or just hashes)
- Remove the legacy hash field to eliminate the conflict
- Investigate if the conflict is unexpected as it may indicate file corruption or tampering
Example fix
# before
data = {
"url": "https://example.com/pkg.tar.gz",
"archive_info": {
"hash": "sha256=old_value",
"hashes": {"sha256": "new_value"} # mismatched
}
}
# after
import hashlib
correct = hashlib.sha256(file_bytes).hexdigest()
data = {
"url": "https://example.com/pkg.tar.gz",
"archive_info": {"hashes": {"sha256": correct}}
} Defensive patterns
Strategy: validation
Validate before calling
def validate_hash_value_match(archive_info: dict) -> None:
legacy = archive_info.get("hash")
hashes = archive_info.get("hashes")
if legacy and hashes:
algo, digest = legacy.split("=", 1)
if algo in hashes and hashes[algo] != digest:
raise ValueError(f"Hash mismatch for {algo!r}: legacy={digest!r} vs hashes={hashes[algo]!r}") Type guard
def do_hash_values_match(archive_info: dict) -> bool:
legacy = archive_info.get("hash")
hashes = archive_info.get("hashes")
if not legacy or not hashes:
return True
algo, digest = legacy.split("=", 1)
return algo not in hashes or hashes[algo] == digest Try / catch
from packaging.direct_url import DirectUrl, DirectUrlValidationError
try:
du = DirectUrl.from_dict(data)
except DirectUrlValidationError as e:
if "different value" in str(e):
data["archive_info"].pop("hash")
du = DirectUrl.from_dict(data) Prevention
- Never manually edit hash fields
- Regenerate both hash representations from the same computation
- Drop legacy hash fields when migrating to hashes
When it happens
Trigger: An archive_info block where the same algorithm appears in both hash and hashes with different digest values: e.g. {'hash': 'sha256=aaa', 'hashes': {'sha256': 'bbb'}}.
Common situations: Metadata edited by hand or by buggy tools. Hash recomputation that updated one field but not the other. Potential supply-chain integrity concern if the conflict is unexpected.
Related errors
- Algorithm used in hash field is not present in hashes field
- Hash values must be strings
- Invalid hash format (expected ' = ')
- Exactly one of vcs_info, archive_info, dir_info must be…
- File URL must be absolute when dir_info is present
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/a4d2794b5a795b26.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/direct_url.py:224
if "=" not in legacy_hash:
raise DirectUrlValidationError(
"Invalid hash format (expected '<algorithm>=<hash>')",
context="hash",
)
hash_algorithm, hash_value = legacy_hash.split("=", 1)
if hashes is None:
# if `hashes` are not present, we can derive it from the legacy `hash`
hashes = {hash_algorithm: hash_value}
else:
# if `hashes` are present, the legacy `hash` must match one of them
if hash_algorithm not in hashes:
raise DirectUrlValidationError(
f"Algorithm {hash_algorithm!r} used in hash field "
f"is not present in hashes field",
context="hashes",
)
if hashes[hash_algorithm] != hash_value:
raise DirectUrlValidationError(
f"Algorithm {hash_algorithm!r} used in hash field "
f"has different value in hashes field",
context="hash",
)
return cls(hashes=hashes)
@dataclasses.dataclass(frozen=True, init=False)
class DirInfo:
"""The local directory information of a :class:`DirectUrl`."""
editable: bool | None = None
def __init__(
self,
*,
editable: bool | None = None,
) -> None:View on GitHub (pinned to f399c37189)