DEV Community

Cover image for Understanding the A2A Task Lifecycle (and the Bug That Hangs Every Client)
PromptMaster
PromptMaster

Posted on

Understanding the A2A Task Lifecycle (and the Bug That Hangs Every Client)

A2A is task-centric. Once a client sends work, that work becomes a Task with a lifecycle you can observe from submission to completion — if your agent reports it honestly.


A Task is the central, stateful unit of work in A2A. It is created when a client sends its first Message and moves through defined states until it reaches a terminal one.

The states are: submitted, working, input-required, completed, failed, and canceled. The last three are terminal.

The rule that matters most: every Task must reach a terminal state. A client that never hears one waits forever — and that is the single most common bug in early A2A implementations.


Why A2A models tasks instead of calls

The instinct from REST is to treat each call as independent: send a request, get a response, done. Agent work rarely behaves like that.

A report might take minutes. A data pipeline might take an hour. A design task might need a clarifying question halfway through. Modeling all of that as a single request-response call means pretending every call returns at once — and then bolting on workarounds when it doesn't.

A2A models it honestly instead: work becomes a Task with an explicit state machine, so both sides always agree on where things stand.

The six states

  • submitted — the Task has been received but work has not yet begun.
  • working — the remote agent is actively processing the Task.
  • input-required — the agent needs more information and is waiting on the client before it can continue.
  • completed — the Task finished successfully; Artifacts are available.
  • failed — the Task ended in error.
  • canceled — the Task was stopped by request.

The last three are terminal: once a Task reaches one, it is over.

The four methods you need

A client starts a Task by sending a Message; the response carries the Task, including its identifier and current state. From there:

message/send     # send a message; create or continue a task
message/stream   # send a message and subscribe to live updates
tasks/get        # retrieve a task's current state and artifacts
tasks/cancel     # cancel an in-progress task
Enter fullscreen mode Exit fullscreen mode

That's the whole surface. Most of the protocol's power comes from what these four methods operate on — a stateful, observable Task — not from method count.

input-required is a feature, not an error

Real delegation is rarely one-shot. The input-required state lets a remote agent pause and ask a clarifying question mid-task, then resume when the client answers.

Follow one task through to see it: a client asks an agent to generate a report; the task is created as submitted. The agent begins and moves it to working. Partway through it realizes it needs a date range, so it moves the task to input-required and asks. The client supplies the range; the task returns to working. When the report is ready, the agent attaches it as an Artifact and moves the task to completed.

event: task state -> working
event: message  -> "Which time range should I cover?"
event: task state -> input-required

# client replies on the SAME task
event: task state -> working
event: task state -> completed
Enter fullscreen mode Exit fullscreen mode

Same task throughout. No new task, no lost context. That turns a rigid call into a genuine collaboration.

The bug that hangs every client

Here it is, plainly: a remote agent finishes its work but never reports a terminal state, so the client waits indefinitely.

The work completed. The logs look fine. The agent is idle and happy. And the caller is still sitting there, because as far as the protocol is concerned, that Task never ended.

Always emit a terminal event — including on error paths, especially on error paths. If a client of yours hangs, this is the first thing to check, and it will usually be the answer.

Every Task must reach a terminal state.*Not most tasks. Every task, on every path.*

Three ways to track a task

The underlying Task is identical in all three; only how you receive updates changes.

When to use How
Polling Simple, short work where live progress doesn't matter Call tasks/get by task id
Streaming Interactive work someone is waiting on message/stream over Server-Sent Events
Push notifications Long, unattended work — minutes to hours Register a callback; disconnect; get notified on state change

For the longest jobs, prefer push notifications over holding a stream open for hours. You avoid a fragile long-lived connection and the task model doesn't change.

Why an explicit lifecycle pays off

Modeling tasks as stateful, observable objects is what makes A2A suitable for real work rather than toy demos:

  • You can build dashboards showing every in-flight task.
  • You can write retry logic that reacts to failed states.
  • You can build orchestration that waits on completed before triggering the next step.
  • You can trace a failure across every agent a task touched, instead of guessing.

The lifecycle is not bureaucracy. It is the observability layer that lets multi-agent systems be operated, not just launched.

Contexts group related tasks

Real work is rarely a single task. A2A lets related tasks share a context, so an agent can connect a follow-up request to earlier ones and reason about the whole thread rather than each request in isolation.

This is what turns a sequence of one-off delegations into a coherent, ongoing collaboration — the agent equivalent of remembering the conversation so far.

Frequently asked questions

What are the A2A task states?
submitted, working, input-required, completed, failed, and canceled. The last three are terminal — once a task reaches one, it's over.

What does input-required mean in A2A?
The remote agent needs more information and has paused, waiting on the client. It's a feature, not an error: it lets an agent ask a clarifying question mid-task and resume on the same task when the client answers.

Why does my A2A client hang forever?
Almost always because the remote agent finished its work but never emitted a terminal state. The protocol has no way to know the task ended, so the client keeps waiting. Always emit completed, failed, or canceled — on every path, including errors.

Should I poll or stream A2A tasks?
Poll with tasks/get for simple short work. Stream with message/stream for interactive work someone is waiting on. Use push notifications for long unattended jobs where holding a connection open for hours is wasteful.

Is an A2A task the same as an HTTP request?
No. An HTTP request is stateless and returns once. An A2A task is stateful, can run for a long time, can pause for input, and can stream many updates before reaching a terminal state.


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)