{"record":{"id":"b47c556bb64935c6","repo":"BerriAI/litellm","slug":"cannot-retry-a2a-localhost-url-fix-no-agent-card","errorCode":null,"errorMessage":"Cannot retry A2A localhost URL fix: no agent card is available to rewrite, so the upstream URL cannot be corrected.","messagePattern":"Cannot retry A2A localhost URL fix: no agent card is available to rewrite, so the upstream URL cannot be corrected\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"litellm/a2a_protocol/exception_mapping_utils.py","lineNumber":188,"sourceCode":"    with the corrected URL.\n\n    Args:\n        error: The localhost URL error\n        agent_card: The agent card object to fix\n        a2a_client: The current A2A client\n        is_streaming: Whether this is a streaming request (for logging)\n\n    Returns:\n        A new A2A client with the fixed URL\n\n    Raises:\n        ImportError: If the A2A SDK is not installed\n    \"\"\"\n    if not A2A_SDK_AVAILABLE:\n        raise ImportError(\"A2A SDK is required for localhost retry handling. Install it with: pip install a2a-sdk\")\n\n    if agent_card is None:\n        raise RuntimeError(\n            \"Cannot retry A2A localhost URL fix: no agent card is available to \"\n            \"rewrite, so the upstream URL cannot be corrected.\"\n        )\n\n    request_type: Final = \"streaming \" if is_streaming else \"\"\n    verbose_logger.warning(\n        \"A2A %srequest to '%s' failed: %s. Agent card contains localhost/internal URL. Retrying with base_url '%s'.\",\n        request_type,\n        error.localhost_url,\n        error.original_error,\n        error.base_url,\n    )\n\n    # Fix the agent card URL\n    set_agent_card_url(agent_card, error.base_url)\n\n    # Reuse the httpx client and call context LiteLLM attached at creation, since the\n    # context carries this agent's trace-id/auth headers. Only clients built by","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/a2a_protocol/exception_mapping_utils.py#L170-L206","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass api_base instead of a2a_client so litellm fetches the card and can perform the retry","Or create the client via litellm.a2a_protocol.create_a2a_client(base_url=...) so the card flow stays intact","Fix the agent's advertised URL so the localhost retry is never needed"],"exampleFix":"# before\nclient = my_own_builder.build()  # no agent card in litellm\nawait asend_message(a2a_client=client, request=req)\n\n# after\nawait asend_message(api_base='http://agent-svc:10001', request=req)","handlingStrategy":"validation","validationCode":"# The retry needs a card; only litellm-created flows have one.\n# Prefer api_base over an external client when the agent may advertise localhost:\nif a2a_client_was_built_externally:\n    await asend_message(api_base=api_base, request=req)  # card fetched internally\nelse:\n    await asend_message(a2a_client=a2a_client, request=req, api_base=api_base)","typeGuard":"from typing import Any, TypeGuard\n\n\ndef client_has_retry_support(client: Any) -> TypeGuard[Any]:\n    \"\"\"True when the client was built by create_a2a_client (has the litellm\n    httpx client attached), so localhost retries are possible.\"\"\"\n    return getattr(client, '_litellm_httpx_client', None) is not None","tryCatchPattern":"try:\n    resp = await asend_message(a2a_client=my_client, request=req)\nexcept RuntimeError as e:\n    if 'no agent card is available' in str(e):\n        # fall back to the card-aware path\n        resp = await asend_message(api_base=api_base, request=req)\n    else:\n        raise","preventionTips":["Default to passing api_base; pass a client only when you must","If you manage clients, create them with litellm.a2a_protocol.create_a2a_client","Keep the agent card's advertised URL correct so retries are never needed"],"tags":["a2a","agent-card","retry","runtime-error"],"backgroundTag":"retry-precondition-missing","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}