BerriAI/litellm · error · ValueError
api_base is required for A2A provider
Error message
api_base is required for A2A provider
What it means
ValueError raised by the A2A provider's get_url when api_base is None. A2A agents are addressed entirely by their base URL (JSON-RPC 2.0 at that URL; the model name does not select a host), so without api_base the request cannot be routed anywhere and fails fast.
Solutions
- Pass api_base explicitly: litellm.completion(model='a2a/x', api_base='http://host:9999', ...).
- In proxy config, add litellm_params: {model: a2a/x, api_base: http://host:9999} to the model_list entry.
- Check for key typos (base_url vs api_base) and that the value is not None/empty.
- Verify the agent is reachable at that URL and speaks A2A JSON-RPC 2.0 at the base path.
Example fix
# before
resp = litellm.completion(model="a2a/agent", messages=[{"role": "user", "content": "hi"}])
# ValueError: api_base is required for A2A provider
# after
resp = litellm.completion(
model="a2a/agent",
api_base="http://localhost:9999",
messages=[{"role": "user", "content": "hi"}],
) Defensive patterns
Strategy: validation
Validate before calling
api_base = kwargs.get("api_base") or os.getenv("A2A_API_BASE")
if not api_base:
raise ValueError("api_base is required for A2A provider (e.g. http://localhost:9999)")
resp = litellm.completion(model="a2a/agent", api_base=api_base, messages=messages) Type guard
def is_valid_a2a_target(api_base: object) -> bool:
if not isinstance(api_base, str) or not api_base.strip():
return False
return api_base.startswith(("http://", "https://")) Try / catch
try:
resp = litellm.completion(model="a2a/agent", messages=messages, api_base=api_base)
except ValueError as e:
if "api_base is required" in str(e):
raise HTTPException(status_code=400, detail="A2A deployment is missing api_base")
raise Prevention
- Lint proxy config at startup: every model_list entry whose model starts with a2a/ must define litellm_params.api_base.
- Remember the A2A model name selects the agent, not the host — the URL is the routing key.
- Health-check the api_base URL (it must answer JSON-RPC 2.0) during deployment validation.
When it happens
Trigger: litellm.completion(model='a2a/my_agent', ...) with no api_base in the call, deployment, or litellm_params; api_base set under a misspelled key (base_url) or only in an unrelated env var.
Common situations: First-time A2A usage assuming a default agent registry; proxy deployments whose model_list entry for the a2a model lacks litellm_params.api_base; config migrated from another provider where the base URL key differs.
Related errors
- api_base is required for A2A provider. Either provide…
- api_base is required for Pydantic AI agents
- api_base is required for Pydantic AI agents
- api_base is required for PydanticAIProviderConfig
- A2A SDK is required for localhost retry handling. Install…
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/d72dccfb8e032611.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/a2a/chat/transformation.py:185
Get the complete A2A agent endpoint URL.
A2A agents use JSON-RPC 2.0 at the base URL, not specific paths.
The method (message/send or message/stream) is specified in the
JSON-RPC request body, not in the URL.
Args:
api_base: Base URL of the A2A agent (e.g., "http://0.0.0.0:9999")
api_key: API key (not used for URL construction)
model: Model name (not used for A2A, agent determined by api_base)
optional_params: Optional parameters
litellm_params: LiteLLM parameters
stream: Whether this is a streaming request (affects JSON-RPC method)
Returns:
Complete URL for the A2A endpoint (base URL)
"""
if api_base is None:
raise ValueError("api_base is required for A2A provider")
# A2A uses JSON-RPC 2.0 at the base URL
# Remove trailing slash for consistency
return api_base.rstrip("/")
def transform_request(
self,
model: str,
messages: list[AllMessageValues],
optional_params: dict,
litellm_params: dict,
headers: dict,
) -> dict:
"""
Transform OpenAI request to A2A JSON-RPC 2.0 format.
Args:
model: Model nameView on GitHub (pinned to 77b7c6c40c)