MemPalace/mempalace · error · ValueError

LLM_ENDPOINT must use http:// or https:// (got scheme {schem

Error message

LLM_ENDPOINT must use http:// or https:// (got scheme {scheme!r})

What it means

Raised by the ClosetLLM constructor when LLM_ENDPOINT (or the --endpoint argument) has a URL scheme other than http or https. This is a deliberate privacy-by-architecture guard: the HTTP client could otherwise be pointed at file:// (or other schemes some clients honor), letting a misconfigured or injected endpoint read and exfiltrate local files. Only plain HTTP endpoints — local (Ollama, vLLM, LM Studio) or explicit BYOK cloud — are permitted.

Source

Thrown at mempalace/closet_llm.py:112

class LLMConfig:
    """Resolved LLM connection config. CLI flags > env vars."""

    def __init__(
        self,
        endpoint: Optional[str] = None,
        key: Optional[str] = None,
        model: Optional[str] = None,
    ):
        self.endpoint = (endpoint or os.environ.get("LLM_ENDPOINT", "")).rstrip("/")
        self.key = key or os.environ.get("LLM_KEY", "")
        self.model = model or os.environ.get("LLM_MODEL", "")
        if self.endpoint:
            # Privacy-by-architecture: reject file:// and other non-HTTP schemes
            # so a misconfigured endpoint cannot exfiltrate local files.
            scheme = urllib.parse.urlparse(self.endpoint).scheme.lower()
            if scheme not in ("http", "https"):
                raise ValueError(
                    f"LLM_ENDPOINT must use http:// or https:// (got scheme {scheme!r})"
                )

    def missing(self) -> list:
        missing = []
        if not self.endpoint:
            missing.append("LLM_ENDPOINT (or --endpoint)")
        if not self.model:
            missing.append("LLM_MODEL (or --model)")
        # key is optional — local inference servers (Ollama, vLLM) often don't require one
        return missing


def _call_llm(cfg: LLMConfig, source_file: str, wing: str, room: str, content: str):
    """Single LLM call via OpenAI-compatible /chat/completions.

    Returns (parsed_json_dict_or_None, usage_dict_or_None).
    """

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Set the endpoint with an explicit scheme: LLM_ENDPOINT=http://localhost:11434 for Ollama, https://... for cloud BYOK
  2. If you intended a unix socket, point at the HTTP listen address of the local runtime instead
  3. Audit the environment/hook config that injects LLM_ENDPOINT for a stale file:// value

Example fix

# before
export LLM_ENDPOINT="localhost:11434"   # scheme '' -> ValueError

# after
export LLM_ENDPOINT="http://localhost:11434"
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

endpoint = os.environ.get("LLM_ENDPOINT", "")
if endpoint and urlparse(endpoint).scheme.lower() not in ("http", "https"):
    endpoint = "http://" + endpoint  # fix missing scheme for localhost runtimes
os.environ["LLM_ENDPOINT"] = endpoint

Type guard

def is_http_endpoint(url: str) -> bool:
    return urlparse(url).scheme.lower() in ("http", "https")

Try / catch

try:
    llm = ClosetLLM()
except ValueError as exc:
    if "LLM_ENDPOINT" in str(exc):
        raise SystemExit(f"fix LLM_ENDPOINT: {exc} (use http://host:port)") from None
    raise

Prevention

When it happens

Trigger: Constructing the LLM client with endpoint='file:///etc/passwd', LLM_ENDPOINT='unix:///run/ollama.sock', an empty-scheme value like 'localhost:11434' (parsed scheme becomes ''), or any gopher/ftp/file URL. Note the check fires only when the endpoint is non-empty.

Common situations: Forgetting the http:// prefix (LLM_ENDPOINT=localhost:11434 — urlparse yields scheme ''); trying to use a unix socket URL; a .env or hook config carrying a file:// path copied from another tool; typo like http:/ (single slash still parses as http, but htp:// does not).

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/8fb5663add098213. Report an issue: GitHub.