{"id":"a4d2794b5a795b26","repo":"pypa/pip","slug":"algorithm-hash-algorithm-r-used-in-hash-field-ha","errorCode":null,"errorMessage":"Algorithm {hash_algorithm!r} used in hash field has different value in hashes field","messagePattern":"Algorithm (.+?) used in hash field has different value in hashes field","errorType":"validation","errorClass":"DirectUrlValidationError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/direct_url.py","lineNumber":212,"sourceCode":"            if \"=\" not in legacy_hash:\n                raise DirectUrlValidationError(\n                    \"Invalid hash format (expected '<algorithm>=<hash>')\",\n                    context=\"hash\",\n                )\n            hash_algorithm, hash_value = legacy_hash.split(\"=\", 1)\n            if hashes is None:\n                # if `hashes` are not present, we can derive it from the legacy `hash`\n                hashes = {hash_algorithm: hash_value}\n            else:\n                # if `hashes` are present, the legacy `hash` must match one of them\n                if hash_algorithm not in hashes:\n                    raise DirectUrlValidationError(\n                        f\"Algorithm {hash_algorithm!r} used in hash field \"\n                        f\"is not present in hashes field\",\n                        context=\"hashes\",\n                    )\n                if hashes[hash_algorithm] != hash_value:\n                    raise DirectUrlValidationError(\n                        f\"Algorithm {hash_algorithm!r} used in hash field \"\n                        f\"has different value in hashes field\",\n                        context=\"hash\",\n                    )\n        return cls(hashes=hashes)\n\n\n@dataclasses.dataclass(frozen=True, init=False)\nclass DirInfo:\n    editable: bool | None = None\n\n    def __init__(\n        self,\n        *,\n        editable: bool | None = None,\n    ) -> None:\n        object.__setattr__(self, \"editable\", editable)\n","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/direct_url.py#L194-L230","documentation":"Raised by `ArchiveInfo._from_dict` when both `hashes` and legacy `hash` are present, the algorithm matches a key in `hashes`, but the digest value differs. This signals that the two fields disagree about the package's content hash — treated as a potential tampering/corruption indicator.","triggerScenarios":"A record like `hashes: {\"sha256\": \"aaa\"}` and legacy `hash: \"sha256=bbb\"` — same algorithm, conflicting digests.","commonSituations":"A wheel was re-published with new content but the legacy `hash` field was not updated; partial edits to install metadata; a corrupted or man-in-the-middle tampered record.","solutions":["Recompute the hash of the actual archive and update both fields consistently","Remove the legacy `hash` field and keep only `hashes`","Reinstall the package from a trusted index to regenerate clean metadata"],"exampleFix":"// before\n{'archive_info': {'hashes': {'sha256':'aaa'}, 'hash': 'sha256=bbb'}}\n// after\n{'archive_info': {'hashes': {'sha256':'aaa'}, 'hash': 'sha256=aaa'}}","handlingStrategy":"validation","validationCode":"def verify_hash_consistency(hashes: dict, legacy_hash: str) -> None:\n    algo, value = legacy_hash.split('=', 1)\n    if hashes is not None and hashes.get(algo) != value:\n        raise ValueError(f'conflicting {algo} digest between hashes and legacy hash')","typeGuard":"def hash_values_match(hashes: dict, legacy_hash: str) -> bool:\n    algo, value = legacy_hash.split('=', 1)\n    return hashes is None or hashes.get(algo) == value","tryCatchPattern":"from packaging.direct_url import ArchiveInfo, DirectUrlValidationError\ntry:\n    ArchiveInfo._from_dict(d)\nexcept DirectUrlValidationError as e:\n    if 'different value' in str(e):\n        log.error('hash mismatch — possible corruption, reinstalling')\n        d['archive_info'].pop('hash', None)\n    raise","preventionTips":["Treat hash conflicts as integrity violations — recompute from the artifact","Single-source hashes into one field only","Reinstall from a trusted index when conflicts surface"],"tags":["packaging","direct-url","pep610","hashes","integrity"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}