BerriAI/litellm · error · ValueError

Compresr guardrail api_base has no host

Error message

Compresr guardrail api_base has no host

What it means

ValueError from _validate_api_base when the configured Compresr api_base parses to an empty host — urlparse(url).hostname is None (or empty) even though the URL string is non-empty. Typical shapes are 'http://:8080', 'http:///path', or URLs where everything landed in scheme/path. The guardrail refuses to initialize against a hostless target; this is part of the SSRF defense-in-depth checks.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/compresr/compresr.py:137

    return addr


def _validate_api_base(url: str) -> str:
    """Return ``url`` if it passes basic outbound-target checks, else raise.

    Best-effort defense in depth for a mis/maliciously-configured ``api_base``:
    rejects non-http(s) schemes and cloud-metadata IPs/hosts (incl. alternate IP
    encodings); private ranges are allowed for on-prem deployments. NOT a complete
    SSRF control — no DNS resolution, and the shared client follows redirects and
    re-resolves DNS (TOCTOU / rebinding); ``api_base`` is trusted operator config,
    so this is an accepted limitation.
    """
    parsed: Final = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        raise ValueError(f"Compresr guardrail api_base must be http or https, got scheme={parsed.scheme!r}")
    host: Final = (parsed.hostname or "").lower()
    if not host:
        raise ValueError("Compresr guardrail api_base has no host")
    ip_literal: Final = _parse_ip_literal(host)
    if host in _BLOCKED_METADATA_HOSTS or (ip_literal is not None and ip_literal in _BLOCKED_METADATA_IPS):
        raise ValueError(f"Compresr guardrail api_base {host!r} is a blocked cloud-metadata host")
    return url


def _is_str_object_dict(value: object) -> TypeGuard[dict[str, object]]:  # guard-ok: isinstance narrows correctly; predicate is trivially correct  # fmt: skip
    return isinstance(value, dict)


def _is_object_list(value: object) -> TypeGuard[list[object]]:  # guard-ok: isinstance narrows correctly; predicate is trivially correct  # fmt: skip
    return isinstance(value, list)


def _replace_text_in_content(content: object, new_text: str) -> object:
    """Write ``new_text`` back into a ``content`` value, preserving shape.

    ``str`` content is replaced directly. An all-text part list collapses to a

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Set a complete api_base with an explicit host: http://host:port or https://api.compresr.io.
  2. Sanity-check: urlparse(api_base).hostname must be non-empty before deploying.
  3. Fix empty COMPRESR_API_BASE env values and restart the proxy.

Example fix

# before
litellm_params:
  guardrail: compresr
  api_base: http://:8080

# after
litellm_params:
  guardrail: compresr
  api_base: http://compresr.internal:8080
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def has_host(url: str) -> bool:
    return bool(urlparse(url).hostname)

assert has_host(cfg_guardrail.get("api_base", "")), "api_base must include a host, e.g. http://compresr.internal:8080"

Type guard

from urllib.parse import urlparse
from typing import TypeGuard
def is_url_with_host(value: object) -> TypeGuard[str]:
    return isinstance(value, str) and bool(urlparse(value).hostname)

Prevention

When it happens

Trigger: api_base values like 'http://' (nothing else), 'http:///v1', 'http://:9000', or malformed strings with stray characters that push the host into other components; also scheme-only values after a bad string substitution in templated configs.

Common situations: Env var COMPRESR_API_BASE accidentally empty-but-prefixed (e.g., 'http://' + empty host); templating producing 'http:///'; copy-paste losing the hostname between slashes.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/ba743bc977cdd367. Report an issue: GitHub.