BerriAI/litellm · error · ValueError

Compresr guardrail api_base must be http or https, got schem

Error message

Compresr guardrail api_base must be http or https, got scheme={parsed.scheme!r}

What it means

ValueError from _validate_api_base when constructing the Compresr guardrail: the configured/derived api_base has a URL scheme other than http or https (the {parsed.scheme!r} of the actual scheme is shown, e.g. 'file', 'ws', 'gcpmetadata'). This is the first check in a defense-in-depth SSRF review of the outbound target — the guardrail refuses to initialize against non-HTTP targets. api_base is operator config, so this fires at startup when the config value is malformed.

Source

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

            return None
    if isinstance(addr, ipaddress.IPv6Address) and addr.ipv4_mapped is not None:
        return addr.ipv4_mapped
    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:

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Fix api_base to a full http(s) URL, e.g., https://api.compresr.example or http://localhost:8080 (note the // — bare host:port is parsed as a scheme).
  2. Verify with urlparse in a REPL: from urllib.parse import urlparse; urlparse(url).scheme must be 'http' or 'https'.
  3. If using COMPRESR_API_BASE, correct the env var and restart the proxy.

Example fix

# before (parsed as scheme='localhost')
litellm_params:
  guardrail: compresr
  api_base: localhost:8080

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

Strategy: validation

Validate before calling

from urllib.parse import urlparse
REQUIRED_SCHEMES = ("http", "https")

def validate_compresr_api_base(url: str) -> str:
    scheme = urlparse(url).scheme.lower()
    if scheme not in REQUIRED_SCHEMES:
        raise ValueError(f"api_base must be http/https, got scheme={scheme!r} — include 'http://' for bare host:port")
    return url

validate_compresr_api_base(cfg_guardrail["api_base"])  # before proxy start

Type guard

from urllib.parse import urlparse
from typing import TypeGuard
def is_http_url(value: object) -> TypeGuard[str]:
    if not isinstance(value, str):
        return False
    p = urlparse(value)
    return p.scheme in ("http", "https") and bool(p.hostname)

Prevention

When it happens

Trigger: Setting api_base: file:///etc/passwd, ws://..., ftp://..., or a schemeless value that urlparse interprets oddly (e.g., 'localhost:8080' where 'localhost' becomes the scheme); passing a Compresr API base copied from a websocket URL or with a typo like 'httpx://'.

Common situations: YAML values without the http:// prefix (localhost:9000 parsed as scheme=localhost); copying ws:// endpoints from Compresr streaming docs; env var COMPRESR_API_BASE containing a trailing fragment or wrong protocol.

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/830abe3700801896. Report an issue: GitHub.