pypa/pip · error · VcsHashUnsupported
Can't verify hashes for these requirements because we don't…
Error message
Can't verify hashes for these requirements because we don't have a way to hash version control repositories:
What it means
Raised by _get_linked_req_hashes (prepare.py:473) as VcsHashUnsupported when pip is in --require-hashes mode and the requirement resolves to a VCS URL (git+/hg+/svn+/bzr+). pip cannot compute a stable cryptographic hash over a version-control checkout, so hash-verification mode is incompatible with VCS requirements.
Solutions
- Remove the VCS requirement from the hashed installation set, or install it separately without --require-hashes.
- Vendor the VCS project into a local wheel/sdist and pin a hash for that artifact instead.
- If only a fixed commit is needed, build a wheel from the checkout and reference the wheel with its hash.
- Do not use --require-hashes for environments that legitimately need editable/VCS installs.
Example fix
# before pip install --require-hashes -r locked.txt # locked.txt contains: git+https://example/repo.git # after: build & hash an artifact instead pip wheel --no-deps git+https://example/repo.git@<commit> -w ./wheels pip install --require-hashes ./wheels/Repo-1.0-py3-none-any.whl --hash sha256:...
Defensive patterns
Strategy: validation
Validate before calling
# Detect VCS requirements before running pip with --require-hashes so they can be excluded/converted.
from pip._internal.vcs import vcs
def is_vcs_requirement(line: str) -> bool:
low = line.lower()
return any(low.startswith(s + ':') or low.startswith(s + '+') for s in vcs.all_schemes)
def no_vcs_in_hashed_file(path: str) -> bool:
with open(path) as f:
return not any(is_vcs_requirement(l.split('#')[0].strip()) for l in f if l.strip()) Type guard
from pip._internal.vcs import vcs
def is_vcs_url(url: str) -> bool:
low = url.lower()
return any(low.startswith(s + ':') or low.startswith(s + '+') for s in vcs.all_schemes) Try / catch
from subprocess import run, CalledProcessError
try:
run(["pip", "install", "--require-hashes", "-r", req_file], check=True)
except CalledProcessError:
# Fallback: build VCS deps into hashed artifacts first.
run(["pip", "wheel", "--no-deps", vcs_url, "-w", "./wheels"], check=True) Prevention
- Keep VCS requirements out of hashed requirement sets.
- Convert VCS deps to built wheels and hash the artifacts.
- Validate requirement files for VCS schemes before enabling --require-hashes.
When it happens
Trigger: Running with --require-hashes (or a hashed requirements file) while installing a VCS requirement like 'git+https://.../repo.git'. Detected via req.link.is_vcs before hashes are checked.
Common situations: A locked/hashed requirements file that accidentally includes a -e git+... editable or a VCS direct reference; mixing a security-pinned environment with a development VCS dependency.
Related errors
- Can't verify hashes for these file:// requirements because…
- In --require-hashes mode, all requirements must have their…
- The editable requirement
- Could not detect requirement name for
- is not a valid editable requirement. It should either be a…
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/c891aa1a416ec578.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/operations/prepare.py:474
parallel_builds=parallel_builds,
)
req.ensure_pristine_source_checkout()
def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes:
# By the time this is called, the requirement's link should have
# been checked so we can tell what kind of requirements req is
# and raise some more informative errors than otherwise.
# (For example, we can raise VcsHashUnsupported for a VCS URL
# rather than HashMissing.)
if not self.require_hashes:
return req.hashes(trust_internet=True)
# We could check these first 2 conditions inside unpack_url
# and save repetition of conditions, but then we would
# report less-useful error messages for unhashable
# requirements, complaining that there's no hash provided.
if req.link.is_vcs:
raise VcsHashUnsupported()
if req.link.is_existing_dir():
raise DirectoryUrlHashUnsupported()
# Unpinned packages are asking for trouble when a new version
# is uploaded. This isn't a security check, but it saves users
# a surprising hash mismatch in the future.
# file:/// URLs aren't pinnable, so don't complain about them
# not being pinned.
if not req.is_direct and not req.is_pinned:
raise HashUnpinned()
# If known-good hashes are missing for this requirement,
# shim it with a facade object that will provoke hash
# computation and then raise a HashMissing exception
# showing the user what the hash should be.
return req.hashes(trust_internet=False) or MissingHashes()
def _fetch_metadata_only(View on GitHub (pinned to f399c37189)