pypa/pip · error · DirectoryUrlHashUnsupported
Can't verify hashes for these file:// requirements because…
Error message
Can't verify hashes for these file:// requirements because they point to directories:
What it means
Raised by _get_linked_req_hashes (prepare.py:475) as DirectoryUrlHashUnsupported when --require-hashes mode encounters a file:// URL pointing at an existing directory. A directory has no single byte stream to hash, so pip cannot satisfy hash verification for directory-based file:// requirements.
Solutions
- Build the local project into a wheel/sdist first, then reference the artifact with its hash.
- Split the install so the local directory is installed without --require-hashes.
- Use an sdist (.tar.gz) of the project and pin its hash instead of the directory.
Example fix
# before pip install --require-hashes file:///path/to/myproject # after python -m build /path/to/myproject pip install --require-hashes /path/to/myproject/dist/myproject-1.0.tar.gz --hash sha256:...
Defensive patterns
Strategy: validation
Validate before calling
import os
def is_dir_file_url(line: str) -> bool:
s = line.split('#')[0].strip()
if s.lower().startswith('file:'):
path = s[5:].lstrip('/')
return os.path.isdir('/' + path if not os.path.isabs(path) else path)
return os.path.isdir(s) and not s.endswith(('.whl', '.tar.gz', '.zip'))
def no_dir_file_urls_in_hashed_file(path: str) -> bool:
with open(path) as f:
return not any(is_dir_file_url(l) for l in f if l.strip()) Type guard
import os
def is_installable_artifact_path(path: str) -> bool:
return os.path.isfile(path) and path.endswith(('.whl', '.tar.gz', '.zip')) Try / catch
from subprocess import run, CalledProcessError
try:
run(["pip", "install", "--require-hashes", "-r", req_file], check=True)
except CalledProcessError:
# Fallback: build the directory into a wheel and hash it.
run(["python", "-m", "build", "--wheel", project_dir], check=True) Prevention
- Build local projects to wheels/sdists and reference artifacts by hash instead of directories.
- Audit hashed requirement files for file:// directory references.
- Split directory installs out of --require-hashes runs.
When it happens
Trigger: Installing from a local directory via 'file:///path/to/project' (or a bare local path resolved to file:) while --require-hashes is active. Detected via req.link.is_existing_dir().
Common situations: A hashed requirements file referencing a local editable/directory install; CI that pins hashes but also installs an in-repo package by path.
Related errors
- Can't verify hashes for these requirements because we don't…
- In --require-hashes mode, all requirements must have their…
- The editable requirement
- Directory is not installable. Neither 'setup.py' nor…
- 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/4122f4fdeec96d27.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/operations/prepare.py:476
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(
self,
req: InstallRequirement,View on GitHub (pinned to f399c37189)