Because a release often has several files, such as a wheel and a source distribution, and each has its own hash. If your requirements list only the hash of the file pip chose before, then a flag that changes the choice makes pip fetch a different file, whose hash is not listed. Add the hashes for every file you allow.
Why one release has many hashes
The pip documentation explains it. A project can offer binary distributions for a variety of platforms, and source distributions as well. Hash-checking mode allows multiple hashes per package, which the guide says is important when a package offers binaries for several platforms or when you must allow both binary and source forms.
When you bootstrap hashes by letting pip report them, the guide notes it fetches only the preferred archive for each package. So you may still need to add hashes for alternative archives.
The pip hash reference puts the failure case directly: the error message gives you one hash, but if there are multiple archives, such as source and binary ones, you need to download and compute hashes for the others. Otherwise a spurious hash mismatch could occur when pip install is passed a different set of options, like the no-binary option.
Typical triggers
| Change | Why pip picks a different file |
|---|---|
| Adding only-binary or no-binary | Changes whether the wheel or sdist is allowed |
| Moving to a new Python version | A different wheel tag matches |
| Building on another operating system or architecture | A different platform wheel matches |
| A new wheel published for a release | Pip may prefer it over the old choice |
None of these means the package was tampered with. The mismatch is pip doing its job: the file it fetched is not in your list.
How to fix it
- Decide which files you will permit: which platforms, which Python versions, wheel only or both.
- Download each one with pip download, or from the index, into a folder.
- Compute the hash of each with the pip hash command.
- Add every allowed hash to the requirement line.
python -m pip download somepackage==1.2.3 --no-deps -d archives
python -m pip hash archives/somepackage-1.2.3-py3-none-any.whl
The hash command computes a digest of a local archive for use as a hash option in a requirements file. It supports sha256, sha384 and sha512. The pip guide recommends sha256 as the current default.
Do not just paste the new hash and move on
When a mismatch appears, treat it as a prompt for one question: is the new file one I intended to allow? If you changed the options on purpose, add its hash. If you did not, find out why the resolved file changed. A surprising mismatch with no option change deserves attention, because that is the exact event hash checking exists to catch.
Check the index page for the release. See whether a new file appeared, and compare file names and upload dates. If a file with the same name has a different hash than before, stop and investigate. See how pip hash checking works and generate hashes for a requirements file.
Keep it maintainable
- Limit the matrix. Fewer platforms and Python versions mean fewer hashes to maintain.
- Use a tool that writes all hashes at once, and review the diff.
- Keep one requirements file per target environment if they differ a lot.
Safeguard's policies and gates can hold a pull request that changes a dependency until it is reviewed, which fits a workflow where every hash change is a deliberate decision. A free scan is available at gold.safeguard.sh/scan.
Quick check
Is a hash mismatch always an attack?
No. Often a different file was selected. But treat each one as a question to answer before adding a hash.
How many hashes should a requirement have?
One for each file you intend to allow, such as each platform wheel and, if permitted, the sdist.
Sources
Last reviewed: 19 October 2026.