Skip to content

A2A can miss decisioning AdcpError and emit a text-only failure under application import graphs #1088

Description

@bokelley

Version

adcp==8.0.0b9

Problem

The A2A executor can route an adcp.decisioning.types.AdcpError through its generic except Exception branch and emit only:

{"kind":"text","text":"Skill execution failed: update_media_buy"}

MCP correctly preserves the same exception as structuredContent.adcp_error.

This is reproducible in our real ASGI app with a LazyPlatformRouter, middleware, and the SDK idempotency wrapper. The server traceback ends with the exact public decisioning class:

adcp.decisioning.types.AdcpError:
AdcpError[INVALID_REQUEST / correctable]: packages.0.bad_field: Extra inputs are not permitted

but ADCPAgentExecutor.execute() reaches the generic handler at a2a_server.py:454, not _send_adcp_error().

The same behavior occurs for decisioning errors raised by our idempotency and not-found paths, so it is not specific to Pydantic or exception chaining.

Suspected cause

adcp.server.a2a_server eagerly builds _DECISIONING_ADCP_ERROR_TYPES through an optional import at module load:

try:
    from adcp.decisioning.types import AdcpError as _DecisioningAdcpError
except Exception:
    _DECISIONING_ADCP_ERROR_TYPES = ()

Catching every exception and caching an empty tuple makes the result import-order/circular-import sensitive in a large application graph. It also hides the reason the structured type was unavailable.

Expected

Every public adcp.decisioning.AdcpError raised from a platform method should produce an A2A failed Task containing DataPart.data.adcp_error, regardless of application import order. This should have parity with MCP.

Current adopter workaround

We had to define an error inheriting both public SDK bases and use it for all platform errors:

from adcp.decisioning import AdcpError as DecisioningAdcpError
from adcp.exceptions import ADCPError as ClientAdcpError

class WireAdcpError(DecisioningAdcpError, ClientAdcpError):
    pass

That restores the A2A adcp_error artifact while remaining catchable by decisioning/MCP dispatch. It would be better for the SDK to remove the eager optional-import dependency (or expose one shared server-side structured-error base/marker).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions