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

  1. Do not use the offending package; report it to PyPI's security team if it appears malicious.
  2. If you control the package, publish the dependency to PyPI instead of referencing an external URL.
  3. If this is your own private/index setup, ensure dependencies also resolve through your index rather than hardcoded external URLs.
  4. 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

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


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/98f444cb7538884c.json. Report an issue: GitHub.