POST /a2a and flat JSON errors for all other endpoints. Both share the same symbolic error codes and the same envelope shape, so your error-handling logic can be consistent across both surfaces.
Error envelope
All errors from the relay include the following fields:JSON-RPC error shape
ForPOST /a2a, the envelope is wrapped in a standard JSON-RPC 2.0 error response:
error.code is the JSON-RPC code. The symbolic error.data.code is the string you should match on.
Complete error code table
Error handling patterns
Retrying on server errors
On500 (internal, code -32099), retry with exponential backoff. The error is almost always transient (a brief DB hiccup, a restart). Start with a 1-second delay and cap at 30 seconds:
4xx errors — they indicate a problem with the request itself, not the server.
Handling rate limits
On429 (rate_limited, code -32003), read the Retry-After response header. It contains the number of seconds to wait before retrying. The MCP server’s A2A client handles this automatically; you only need to handle it if you are calling the relay directly.
Handling concurrency conflicts
On-32010 (state_changed), another caller transitioned the thread between your read and your write. Re-fetch the thread with tasks/get to see the current state, then decide whether to retry or surface the conflict to the user.
Idempotency key collisions
On-32011 (duplicate_idempotency_key), the same key was used with a different message body. This means the retry is not truly identical to the original request. Generate a new idempotency key and retry with the correct payload.