chroma-core/chroma · error · ValueError

Invalid URL. Unrecognized protocol - {parsed.scheme}.

Error message

Invalid URL. Unrecognized protocol - {parsed.scheme}.

What it means

Host validation in BaseHTTPClient.resolve_url(): the host string contains a '/' and urlparse() extracted a scheme that is not http or https. Chroma accepts either a bare hostname/IP or a full http(s):// URL; anything else with a slash is rejected. Notably, urlparse('localhost:8000/api') yields scheme 'localhost', so passing host:port/path as the host trips this exact branch with "Unrecognized protocol - localhost".

Source

Thrown at chromadb/api/base_http_client.py:54

        max_connections = self._settings.chroma_http_max_connections
        if max_connections is not None:
            limit_kwargs["max_connections"] = max_connections

        max_keepalive_connections = self._settings.chroma_http_max_keepalive_connections
        if max_keepalive_connections is not None:
            limit_kwargs["max_keepalive_connections"] = max_keepalive_connections

        return httpx.Limits(**limit_kwargs)

    @property
    def http_limits(self) -> httpx.Limits:
        return self._http_limits

    @staticmethod
    def _validate_host(host: str) -> None:
        parsed = urlparse(host)
        if "/" in host and parsed.scheme not in {"http", "https"}:
            raise ValueError(
                "Invalid URL. " f"Unrecognized protocol - {parsed.scheme}."
            )
        if "/" in host and (not host.startswith("http")):
            raise ValueError(
                "Invalid URL. "
                "Seems that you are trying to pass URL as a host but without \
                  specifying the protocol. "
                "Please add http:// or https:// to the host."
            )

    @staticmethod
    def resolve_url(
        chroma_server_host: str,
        chroma_server_ssl_enabled: Optional[bool] = False,
        default_api_path: Optional[str] = "",
        chroma_server_http_port: Optional[int] = 8000,
    ) -> str:
        _skip_port = False

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Pass a bare hostname and use the port argument: HttpClient(host="localhost", port=8000).
  2. If you intend to pass a full URL, prefix it with http:// or https:// (e.g. host="http://localhost:8000").
  3. Move any API path out of the host — the client builds the path itself.

Example fix

# before
client = HttpClient(host="localhost:8000/api/v2")  # ValueError: Unrecognized protocol - localhost

# after
client = HttpClient(host="localhost", port=8000)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def valid_chroma_host(host: str) -> bool:
    parsed = urlparse(host)
    return "/" not in host or parsed.scheme in {"http", "https"}

assert valid_chroma_host("localhost:8000/api") is False  # would raise in the client
assert valid_chroma_host("localhost") is True

Try / catch

try:
    client = chromadb.HttpClient(host=host, port=port)
except ValueError as e:  # raised from resolve_url host validation
    raise ValueError(f"Fix the host setting {host!r}: {e}") from e

Prevention

When it happens

Trigger: HttpClient(host="localhost:8000/api/v2") — the port belongs in the port argument; host="ftp://box" or host="tcp://box"; any scheme-prefixed string other than http/https.

Common situations: Pasting a URL copied from docs or a browser into the host parameter; migrating config from another SDK that takes a full DSN; putting the API path in the host.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/e343d82b22f1fb85. Report an issue: GitHub.