BerriAI/litellm · error · ValueError

api_base is required for LangGraph. Set it via…

Error message

api_base is required for LangGraph. Set it via LANGGRAPH_API_BASE env var or api_base parameter.

What it means

LangGraphConfig.get_complete_url must build {api_base}/runs/stream (streaming) or {api_base}/runs/wait (non-streaming). Unlike some providers there is no default base URL, so when api_base is None (neither the api_base parameter nor LANGGRAPH_API_BASE env var resolved) it raises ValueError before any HTTP call is made.

Solutions

  1. Pass api_base explicitly: litellm.completion(model="langgraph/<assistant>", api_base="https://my-langgraph-server", ...)
  2. Or export LANGGRAPH_API_BASE=https://my-langgraph-server in the process that makes the call and restart it
  3. If routing through the LiteLLM proxy, set api_base on the langgraph deployment in config.yaml
  4. Confirm with printenv LANGGRAPH_API_BASE from the same runtime environment

Example fix

// before
await litellm.acompletion(
    model="langgraph/agent",
    messages=[{"role": "user", "content": "hi"}],
)  # ValueError: api_base is required for LangGraph

// after
await litellm.acompletion(
    model="langgraph/agent",
    messages=[{"role": "user", "content": "hi"}],
    api_base="https://my-langgraph-server",  # or export LANGGRAPH_API_BASE=...
)
Defensive patterns

Strategy: validation

Validate before calling

import os

LANGGRAPH_BASE = os.getenv("LANGGRAPH_API_BASE")
if not LANGGRAPH_BASE:
    raise SystemExit("Set LANGGRAPH_API_BASE (e.g. https://my-langgraph-server) before starting")
# then: litellm.completion(model="langgraph/<assistant>", api_base=LANGGRAPH_BASE, ...)

Try / catch

try:
    litellm.completion(model="langgraph/<assistant>", messages=msgs)
except ValueError as e:
    if "api_base is required for LangGraph" in str(e):
        raise ConfigError("LANGGRAPH_API_BASE missing") from e
    raise

Prevention

When it happens

Trigger: litellm.completion(model="langgraph/<assistant>", ...) with neither an api_base kwarg nor LANGGRAPH_API_BASE set in the calling process; using stream=True only changes the endpoint (/runs/stream), the api_base requirement is identical.

Common situations: Env var missing in the deployed container/CI; k8s secret not mounted; .env not loaded; proxy deployment entry for a langgraph model missing api_base.

Related errors


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

Appendix: source

Thrown at litellm/llms/langgraph/chat/transformation.py:106

        return optional_params

    def get_complete_url(
        self,
        api_base: str | None,
        api_key: str | None,
        model: str,
        optional_params: dict,
        litellm_params: dict,
        stream: bool | None = None,
    ) -> str:
        """
        Get the complete URL for the LangGraph request.

        Streaming: /runs/stream
        Non-streaming: /runs/wait
        """
        if api_base is None:
            raise ValueError(
                "api_base is required for LangGraph. Set it via LANGGRAPH_API_BASE env var or api_base parameter."
            )

        # Remove trailing slash if present
        api_base = api_base.rstrip("/")

        # Choose endpoint based on streaming mode
        if stream:
            return f"{api_base}/runs/stream"
        else:
            return f"{api_base}/runs/wait"

    def _get_assistant_id(self, model: str, optional_params: dict) -> str:
        """
        Get the assistant ID from model or optional_params.

        model format: "langgraph/assistant_id" or just "assistant_id"
        """

View on GitHub (pinned to 77b7c6c40c)