Most A2A trouble comes from a short list of avoidable mistakes. Here they are, with the fix for each.*
The five that account for most A2A trouble: never emitting a terminal state, a missing or vague Agent Card, trusting peers by default, confusing A2A with MCP, and ignoring long-running work.
Almost all of them share one root cause: treating A2A like a simple function call. It's a protocol for stateful, long-running, cross-trust collaboration.
Design for that reality and the pitfalls mostly disappear on their own.
1. Never emitting a terminal state
The symptom: a client hangs forever on a task that, internally, finished ages ago.
This is the most frequent bug in A2A implementations, and it's maddening precisely because everything looks fine from the agent's side. The work completed. The logs are clean. The agent is idle. Meanwhile the caller is still waiting, because as far as the protocol is concerned that Task never ended.
The fix: always emit a terminal event — completed, failed, or canceled — on every path, especially error paths. If a client of yours hangs, check this first. It will usually be the answer.
Every Task must reach a terminal state.*Not most tasks. Every task, on every path.*
2. A missing or vague Agent Card
The symptom: a perfectly good agent nobody ever calls.
An agent that doesn't serve its card at the well-known path is undiscoverable — clients look there, find nothing, and move on. But there's a subtler version: an agent whose skills are described vaguely is undiscoverable in practice. A skill labeled "processing" tells an orchestrator nothing about whether to use it.
The fix: serve the card, and describe skills the way you'd document a public API — stable ids, plain-language descriptions, expected inputs, the shape of returns, and an example where behavior isn't obvious.
# prove it before wiring anything else
curl https://your-agent.example.com/.well-known/agent-card.json
3. Trusting peers by default
The symptom: an agent that will do anything a caller asks, because the caller speaks A2A.
Speaking a protocol is not a credential. Treating another agent as trusted just because it can reach you is how the tools an agent exposes become the biggest attack surface in your architecture.
The fix: authenticate every request, authorize narrowly with scoped tokens, validate all incoming Parts, and rate-limit. Verify per call, not per session — the peer talking to you now may not be the one from a moment ago. The protocol gives you the mechanisms; using them is on you.
4. Confusing A2A with MCP
The symptom: awkward architecture that fights you at every turn.
Reaching for A2A to connect an agent to a database, or MCP to connect two agents, leads to designs that almost work. Wrapping an agent as a "tool" via MCP holds up right until that agent needs to ask a clarifying question, run for ten minutes, or report progress — because tools don't have a task lifecycle.
| MCP | A2A | |
|---|---|---|
| Other end of the wire | A tool, server, or data source | An independent agent with its own skills |
| Unit of interaction | A tool call or resource read | A Task with a lifecycle |
| Direction | Vertical — reaching down | Horizontal — reaching across |
The fix: ask what's on the other end. A resource? MCP. An agent? A2A. That question answers it every time.
5. Ignoring long-running work
The symptom: a system that's responsive in the demo and unusable the first time a task takes four minutes.
Building only for fast, synchronous replies breaks the moment real work shows up. And real agent work is often slow: a report takes minutes, a pipeline takes an hour, a design task pauses to ask a question.
The fix: design for the task lifecycle from the start. Stream updates with message/stream for interactive work someone is waiting on. Use push notifications for long unattended jobs rather than holding a connection open for hours. Use input-required when you need more information instead of guessing or failing.
The meta-pitfall
Look at the five together and a single root cause shows through: treating A2A like a simple function call.
It isn't. It's a protocol for stateful, long-running, cross-trust collaboration between systems you may not control. Every mistake above is what happens when you design as if the other end were a local function that returns immediately, always succeeds, and can be trusted.
Design for what it actually is, and most of these never come up.
A production-readiness checklist
- Every task emits a terminal state on all paths, including errors.
- The Agent Card is served, accurate, and — where trust matters — signed.
- Authentication and authorization are enforced and scoped on every call.
- Long-running work uses streaming or push notifications, not blocking waits.
- Tasks carry correlation ids and are traceable across every agent they touch.
- Clients read advertised capabilities and degrade gracefully for missing ones.
- Endpoints are rate-limited, timed out, and monitored like any production service.
Operate agents like services
One last thing that isn't a bug so much as a posture. Running many agents is an operations discipline, not just a development one.
Treat each agent as a service with an owner, a version, health checks, and a place in your monitoring. Know which agents call which, so a change or outage in one can be traced to its effect on others. Keep a registry of what exists and what it does, or discovery degrades into tribal knowledge.
The organizations that scale agents well are the ones that operate them with the same rigor they bring to any production service.
Frequently asked questions
Why does my A2A client hang forever?
Almost always because the remote agent finished its work but never emitted a terminal state. Always emit completed, failed, or canceled — on every path, including error paths. It's the most common A2A bug by a wide margin.
Why is nobody calling my A2A agent?
Either it isn't serving its Agent Card at /.well-known/agent-card.json, or its skills are described too vaguely for a client to decide it's the right agent for a job. Serve the card, and write skills like public API documentation.
Can I use MCP to connect two agents?
You can wrap an agent as a tool, and it works until that agent needs to ask a clarifying question, run for ten minutes, or report progress — because tools have no task lifecycle. If the other end is an agent, use A2A.
Is it safe to trust an agent that speaks A2A?
No. Speaking the protocol is not a credential. Authenticate every request, authorize narrowly with scoped tokens, validate all incoming Parts, and rate-limit. Verify per call, not per session.
How do I handle A2A tasks that take a long time?
Stream updates with message/stream for interactive work someone is waiting on, and use push notifications for long unattended jobs. Use input-required to pause and ask when you need more information. Never design only for fast synchronous replies.
More in this series
- A2A vs MCP — A2A vs MCP: The Two Protocols Behind Every Serious AI Agent System
- What Is A2A? — What Is the Agent2Agent Protocol? A Complete Introduction to A2A
- The Agent Card — The Agent Card: How AI Agents Discover Each Other
Want to go deeper?
I wrote two guides on this.
A2A Quick-Start — free, 6 pages. The Agent2Agent protocol in 15 minutes: what it is, the five building blocks, the task lifecycle, and where MCP fits.
A2A: The Complete Guide — 42 pages. 15 chapters, 5 appendices. Discovery, security, building your first agent with the SDK, orchestration patterns, extensions and AP2, production and scaling — plus a full worked example of two agents talking and a 30-day adoption path.
Independent educational content. Not affiliated with, endorsed by, or sponsored by Google, the Linux Foundation, Anthropic, or any vendor named. A2A and MCP are evolving specifications — confirm details against the official specification for your target version.
Top comments (0)