pypa/pip · error · InstallationError
Packages installed from PyPI cannot depend on packages which
Error message
Packages installed from PyPI cannot depend on packages which are not also hosted on PyPI.\n{comes_from.name} depends on {req} What it means
Raised by install_req_from_req_string() when a requirement resolved from a package hosted on PyPI (or TestPyPI) itself depends on a package whose URL is NOT hosted on PyPI's file storage domain. This is a safety guard (constructors.py:470): pip forbids PyPI packages from transparently pulling arbitrary external code, which could be a supply-chain exfiltration or trojan vector.
Source
Thrown at src/pip/_internal/req/constructors.py:470
user_supplied: bool = False,
) -> InstallRequirement:
try:
req = get_requirement(req_string)
except InvalidRequirement as exc:
raise InstallationError(f"Invalid requirement: {req_string!r}: {exc}")
domains_not_allowed = [
PyPI.file_storage_domain,
TestPyPI.file_storage_domain,
]
if (
req.url
and comes_from
and comes_from.link
and comes_from.link.netloc in domains_not_allowed
):
# Explicitly disallow pypi packages that depend on external urls
raise InstallationError(
"Packages installed from PyPI cannot depend on packages "
"which are not also hosted on PyPI.\n"
f"{comes_from.name} depends on {req} "
)
return InstallRequirement(
req,
comes_from,
isolated=isolated,
user_supplied=user_supplied,
)
def install_req_from_parsed_requirement(
parsed_req: ParsedRequirement,
isolated: bool = False,
user_supplied: bool = False,
config_settings: dict[str, str | list[str]] | None = None,View on GitHub (pinned to d7d0d0a394)
Solutions
- Do not use the offending package; report it to PyPI's security team if it appears malicious.
- If you control the package, publish the dependency to PyPI instead of referencing an external URL.
- If this is your own private/index setup, ensure dependencies also resolve through your index rather than hardcoded external URLs.
- As a last resort for trusted internal use, vendor the dependency or host it on your own index.
Example fix
# before (in a package's dependencies on PyPI) # install_requires=["helper @ https://my.server/helper.tar.gz"] # after # Publish 'helper' to PyPI, then: # install_requires=["helper>=1.0"]
Defensive patterns
Strategy: validation
Validate before calling
from pip._internal.models.index import PyPI, TestPyPI
def assert_no_external_dep_from_pypi(req_url: str, comes_from_netloc: str) -> None:
forbidden = {PyPI.file_storage_domain, TestPyPI.file_storage_domain}
if req_url and comes_from_netloc in forbidden:
# req_url starting with http(s):// that is NOT on files.pythonhosted.org
from urllib.parse import urlparse
netloc = urlparse(req_url).netloc
if netloc and netloc not in forbidden:
raise ValueError(f"PyPI package cannot depend on external URL {req_url}") Type guard
null
Try / catch
null
Prevention
- Never publish a package whose dependencies reference external URLs; keep all deps on PyPI.
- Audit install_requires/dependencies for any `name @ url` entries before release.
- Treat this error as a possible supply-chain incident and investigate upstream packages.
When it happens
Trigger: A package on PyPI declares a dependency like `evil @ https://evil.example.com/code` or `git+https://...`. When pip resolves that dependency, comes_from.link.netloc is files.pythonhosted.org (PyPI) but req.url points elsewhere, tripping the check at constructors.py:463-468.
Common situations: A legitimate package mistakenly externalizing a dependency. A typosquatted or compromised package trying to pull external payloads. Using --index-url pointing at a mirror while a dep hardcodes a non-PyPI URL. Test packages on TestPyPI referencing external repos.
Related errors
- THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS
- <dynamic: upload-time missing detail>
- Invalid script entry point name {entry.name!r}: the script w
- The wheel {wheel_path!r} has a file {target_path!r} trying t
- Can't verify hashes for these requirements because we don't
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/98f444cb7538884c.json.
Report an issue: GitHub.