pypa/pip · error · ValueError
Trusted host URL must include a host part
Error message
Trusted host URL must include a host part: {host!r} What it means
Raised as a ValueError by PipSession.add_trusted_host when parse_netloc(host) returns None for the host component, i.e. the --trusted-host value (or a trusted-host entry from pip.conf) has no parseable hostname. A trusted host must carry at least a host part.
Solutions
- Provide a hostname: --trusted-host pypi.org or --trusted-host my.server:8080.
- If using a full URL, ensure it contains a host, e.g. http://my.server.
- Audit pip.conf / requirements for malformed trusted-host entries.
Example fix
# before pip install --trusted-host ":8080" pkg # after pip install --trusted-host my.server:8080 pkg
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlsplit
def trusted_host_has_host(host: str) -> bool:
parsed = host if "://" in host else f"//{host}"
return urlsplit(parsed, allow_fragments=False).hostname is not None
# assert trusted_host_has_host("pypi.org")
# assert not trusted_host_has_host(":8080") Prevention
- Always include a hostname in --trusted-host values.
- Validate trusted-host entries before writing them to pip.conf.
- Avoid passing paths or port-only strings as trusted hosts.
When it happens
Trigger: Passing pip --trusted-host with a port-only or path-only or empty string (e.g. ':8080', '/path', 'http://'), or a malformed trusted-host line in config, so parse_netloc yields no host.
Common situations: Typo in --trusted-host; copy-pasting a URL fragment instead of a host; config automation that emits an empty trusted-host value; trailing slashes or scheme-only strings.
Related errors
- Could not determine appropriate file.
- Could not determine editor to use.
- Editor Subprocess exited with exit code
- Got unexpected number of arguments, expected
- Internal Error.
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/e2c779e5d3bc0ed0.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/network/session.py:426
def add_trusted_host(
self, host: str, source: str | None = None, suppress_logging: bool = False
) -> None:
"""
:param host: It is okay to provide a host that has previously been
added.
:param source: An optional source string, for logging where the host
string came from.
"""
if not suppress_logging:
msg = f"adding trusted host: {host!r}"
if source is not None:
msg += f" (from {source})"
logger.info(msg)
parsed_host, parsed_port = parse_netloc(host)
if parsed_host is None:
raise ValueError(f"Trusted host URL must include a host part: {host!r}")
if (parsed_host, parsed_port) not in self.pip_trusted_origins:
self.pip_trusted_origins.append((parsed_host, parsed_port))
self.mount(
build_url_from_netloc(host, scheme="http") + "/", self._trusted_host_adapter
)
self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter)
if not parsed_port:
self.mount(
build_url_from_netloc(host, scheme="http") + ":",
self._trusted_host_adapter,
)
# Mount wildcard ports for the same host.
self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter)
def iter_secure_origins(self) -> Generator[SecureOrigin, None, None]:
yield from SECURE_ORIGINS
for host, port in self.pip_trusted_origins:View on GitHub (pinned to f399c37189)