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
- 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).
- Verify with urlparse in a REPL: from urllib.parse import urlparse; urlparse(url).scheme must be 'http' or 'https'.
- 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
- Never write host:port without a scheme — urlparse reads the host as the scheme.
- Add a config-lint step that urlparse-checks every guardrail api_base.
- When copying endpoints from docs, confirm the protocol prefix matches what the client library expects (httpx needs http/https).
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
- Compresr guardrail api_base has no host
- Compresr guardrail api_base {host!r} is a blocked cloud-meta
- Compresr guardrail requires an API key. Set `api_key` in the
- max_bytes_per_call must be >= 0 (0 disables the cap; positiv
- Invalid Triton API base: {api_base}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/830abe3700801896.
Report an issue: GitHub.