BerriAI/litellm · error · ValueError

request is required

Error message

request is required

What it means

Raised by litellm.a2a_protocol.asend_message when the standard A2A flow is taken (no custom_llm_provider in litellm_params) and the `request` argument is None. The function needs an A2A SendMessageRequest to forward to the agent, so calling it without one is a programming error.

Source

Thrown at litellm/a2a_protocol/main.py:459

    logging_obj: Final = kwargs.get("litellm_logging_obj")
    trace_id = getattr(logging_obj, "litellm_trace_id", None) if logging_obj else None
    custom_llm_provider: Final = litellm_params.get("custom_llm_provider")

    # Route through completion bridge if custom_llm_provider is set
    if custom_llm_provider:
        if request is None:
            raise ValueError("request is required for completion bridge")
        return await _send_message_via_completion_bridge(
            request=request,
            custom_llm_provider=custom_llm_provider,
            api_base=api_base,
            litellm_params=litellm_params,
            agent_extra_headers=agent_extra_headers,
        )

    # Standard A2A client flow
    if request is None:
        raise ValueError("request is required")

    # Create A2A client if not provided but api_base is available
    if a2a_client is None:
        if api_base is None:
            raise ValueError("Either a2a_client or api_base is required for standard A2A flow")
        trace_id = trace_id or str(uuid.uuid4())
        extra_headers: Final[dict[str, str]] = {"X-LiteLLM-Trace-Id": trace_id}
        if agent_id:
            extra_headers["X-LiteLLM-Agent-Id"] = agent_id
        # Overlay agent-level headers (agent headers take precedence over LiteLLM internal ones)
        if agent_extra_headers:
            extra_headers.update(agent_extra_headers)
        a2a_client = await create_a2a_client(base_url=api_base, extra_headers=extra_headers)

    # Type assertion: a2a_client is guaranteed to be non-None here
    assert a2a_client is not None

    agent_name: Final = _get_a2a_model_info(a2a_client, kwargs)

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Construct an a2a.types.SendMessageRequest (with params=MessageSendParams(message=...)) and pass it as `request`
  2. If you meant to route via a completion-style provider, pass litellm_params containing `custom_llm_provider` so the completion bridge path is used

Example fix

# before
resp = await asend_message(a2a_client=client, request=None)
# after
from a2a.types import MessageSendParams, SendMessageRequest
req = SendMessageRequest(params=MessageSendParams(message=msg))
resp = await asend_message(a2a_client=client, request=req)
Defensive patterns

Strategy: validation

Validate before calling

if request is None:
    raise ValueError("caller bug: request must be an a2a.types.SendMessageRequest")
resp = await asend_message(request=request, a2a_client=client)

Type guard

from a2a.types import SendMessageRequest

def is_send_message_request(r: object) -> bool:
    return isinstance(r, SendMessageRequest) and getattr(r.params, "message", None) is not None

Try / catch

try:
    resp = await asend_message(request=request, a2a_client=client)
except ValueError as e:
    if "request is required" in str(e):
        raise  # programming error: fix the caller, do not retry
    raise

Prevention

When it happens

Trigger: Calling `await asend_message(...)` with request=None (or omitting it) while litellm_params has no `custom_llm_provider` key, e.g. `await asend_message(a2a_client=client)`.

Common situations: Building a generic dispatcher that conditionally constructs the A2A request but forgets the None case; passing only params/messages dict instead of an a2a.types.SendMessageRequest object.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/e7fe5f6ee229c9e2. Report an issue: GitHub.