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).
Version
adcp==8.0.0b9Problem
The A2A executor can route an
adcp.decisioning.types.AdcpErrorthrough its genericexcept Exceptionbranch 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:but
ADCPAgentExecutor.execute()reaches the generic handler ata2a_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_servereagerly builds_DECISIONING_ADCP_ERROR_TYPESthrough an optional import at module load: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.AdcpErrorraised from a platform method should produce an A2A failed Task containingDataPart.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:
That restores the A2A
adcp_errorartifact 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).