BerriAI/litellm · error · ValueError
api_base is required for LangFlow. Set it via…
Error message
api_base is required for LangFlow. Set it via LANGFLOW_API_BASE env var or api_base parameter.
What it means
Raised by LangFlowConfig.get_complete_url when building the LangFlow run URL ({api_base}/api/v1/run/{flow_id}) with api_base=None. LiteLLM cannot form a request without a base URL, so it raises ValueError instead of guessing. The base URL is normally resolved from the api_base parameter or the LANGFLOW_API_BASE environment variable.
Solutions
- Pass api_base explicitly: litellm.completion(model="langflow/<flow_id>", api_base="http://localhost:7860", ...)
- Or set the env var in the process that makes the call: export LANGFLOW_API_BASE=http://localhost:7860, then restart the process
- If calling through the LiteLLM proxy, add api_base to the langflow model deployment in config.yaml
- Verify the variable is visible in the same process: printenv LANGFLOW_API_BASE
Example fix
// before
response = litellm.completion(
model="langflow/abc123-flow-id",
messages=[{"role": "user", "content": "hi"}],
) # ValueError: api_base is required for LangFlow
// after
response = litellm.completion(
model="langflow/abc123-flow-id",
messages=[{"role": "user", "content": "hi"}],
api_base="http://localhost:7860", # or export LANGFLOW_API_BASE=http://localhost:7860
) Defensive patterns
Strategy: validation
Validate before calling
import os
LANGFLOW_BASE = os.getenv("LANGFLOW_API_BASE")
if not LANGFLOW_BASE:
raise SystemExit("Set LANGFLOW_API_BASE before starting (e.g. http://localhost:7860)")
# then: litellm.completion(model="langflow/<flow_id>", api_base=LANGFLOW_BASE, ...) Try / catch
try:
litellm.completion(model="langflow/<flow_id>", messages=msgs, api_base=base)
except ValueError as e:
if "api_base is required" in str(e):
raise ConfigError("LANGFLOW_API_BASE missing") from e
raise Prevention
- Set provider base URLs via env vars in a single checked startup step and fail fast at boot, not per request
- Include api_base explicitly when calling non-default providers instead of relying on ambient env state
- Add printenv-style smoke checks to container entrypoints for LANGFLOW_API_BASE
When it happens
Trigger: Any langflow completion call (e.g. litellm.completion(model="langflow/<flow_id>", ...)) where the URL-building path receives no api_base: neither an api_base kwarg nor a resolvable LANGFLOW_API_BASE env var reached get_complete_url (for example when the config is invoked directly, bypassing _get_openai_compatible_provider_info which would otherwise default to http://localhost:7860).
Common situations: LANGFLOW_API_BASE exported in one shell but the proxy/worker/container runs in a different environment; .env file not loaded by the process; typo in the variable name (e.g. LANGFLOW_APIBASE); passing the base URL under a kwarg the config does not read.
Related errors
- api_base is required for LangGraph. Set it via…
- api_base is required
- api_base is required
- api_base is required for A2A provider. Either provide…
- api_base is required for Azure OpenAI LLM provider. Either…
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/db221b199d3fef2a.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/langflow/chat/transformation.py:98
flow_id: Final = (model.split("/", 1)[1] if "/" in model else model).strip()
if not flow_id:
raise LangFlowError(
status_code=400,
message="flow_id is required; use model langflow/{flow_id}",
)
return flow_id
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:
if api_base is None:
raise ValueError(
"api_base is required for LangFlow. Set it via LANGFLOW_API_BASE env var or api_base parameter."
)
api_base = api_base.rstrip("/")
flow_id: Final = quote(self._get_flow_id(model, optional_params), safe="")
return f"{api_base}/api/v1/run/{flow_id}"
def _get_last_user_message(self, messages: list[AllMessageValues]) -> str:
"""Extract the text of the last user message to use as input_value."""
for msg in reversed(messages):
if msg.get("role") == "user":
content = msg.get("content", "")
if isinstance(content, list):
content = convert_content_list_to_str(msg)
if not isinstance(content, str):
content = str(content)
return content
View on GitHub (pinned to 77b7c6c40c)