BerriAI/litellm · error · RuntimeError

Cannot retry A2A localhost URL fix: no agent card is…

Error message

Cannot retry A2A localhost URL fix: no agent card is available to rewrite, so the upstream URL cannot be corrected.

What it means

The localhost-URL retry works by rewriting the URL inside the agent card that LiteLLM fetched for the request. If handle_a2a_localhost_retry is invoked with agent_card=None — which happens when the caller supplied a pre-built a2a_client and no card was ever fetched — there is nothing to rewrite, so it raises this RuntimeError and the request is not retried.

Solutions

  1. Pass api_base instead of a2a_client so litellm fetches the card and can perform the retry
  2. Or create the client via litellm.a2a_protocol.create_a2a_client(base_url=...) so the card flow stays intact
  3. Fix the agent's advertised URL so the localhost retry is never needed

Example fix

# before
client = my_own_builder.build()  # no agent card in litellm
await asend_message(a2a_client=client, request=req)

# after
await asend_message(api_base='http://agent-svc:10001', request=req)
Defensive patterns

Strategy: validation

Validate before calling

# The retry needs a card; only litellm-created flows have one.
# Prefer api_base over an external client when the agent may advertise localhost:
if a2a_client_was_built_externally:
    await asend_message(api_base=api_base, request=req)  # card fetched internally
else:
    await asend_message(a2a_client=a2a_client, request=req, api_base=api_base)

Type guard

from typing import Any, TypeGuard


def client_has_retry_support(client: Any) -> TypeGuard[Any]:
    """True when the client was built by create_a2a_client (has the litellm
    httpx client attached), so localhost retries are possible."""
    return getattr(client, '_litellm_httpx_client', None) is not None

Try / catch

try:
    resp = await asend_message(a2a_client=my_client, request=req)
except RuntimeError as e:
    if 'no agent card is available' in str(e):
        # fall back to the card-aware path
        resp = await asend_message(api_base=api_base, request=req)
    else:
        raise

Prevention

When it happens

Trigger: Calling asend_message/asend_message_streaming with your own externally-built a2a_client (so litellm never fetched the card), the agent's card advertises localhost, the send fails with a connection error, and the retry path runs with agent_card=None.

Common situations: Teams reusing a shared a2a-sdk Client for connection pooling; wrapper libraries that construct the client themselves and hand it to litellm; upgrading litellm to a version that added this retry precondition.

Related errors


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

Appendix: source

Thrown at litellm/a2a_protocol/exception_mapping_utils.py:188

    with the corrected URL.

    Args:
        error: The localhost URL error
        agent_card: The agent card object to fix
        a2a_client: The current A2A client
        is_streaming: Whether this is a streaming request (for logging)

    Returns:
        A new A2A client with the fixed URL

    Raises:
        ImportError: If the A2A SDK is not installed
    """
    if not A2A_SDK_AVAILABLE:
        raise ImportError("A2A SDK is required for localhost retry handling. Install it with: pip install a2a-sdk")

    if agent_card is None:
        raise RuntimeError(
            "Cannot retry A2A localhost URL fix: no agent card is available to "
            "rewrite, so the upstream URL cannot be corrected."
        )

    request_type: Final = "streaming " if is_streaming else ""
    verbose_logger.warning(
        "A2A %srequest to '%s' failed: %s. Agent card contains localhost/internal URL. Retrying with base_url '%s'.",
        request_type,
        error.localhost_url,
        error.original_error,
        error.base_url,
    )

    # Fix the agent card URL
    set_agent_card_url(agent_card, error.base_url)

    # Reuse the httpx client and call context LiteLLM attached at creation, since the
    # context carries this agent's trace-id/auth headers. Only clients built by

View on GitHub (pinned to 77b7c6c40c)