Skip to content

feat!: unify A2AError hierarchy with transport specific subclasses - #587

Merged
JakubWorek merged 11 commits into
epic/1.0_breaking_changesfrom
jakubworek/unify-error-handling
Jul 22, 2026
Merged

feat!: unify A2AError hierarchy with transport specific subclasses#587
JakubWorek merged 11 commits into
epic/1.0_breaking_changesfrom
jakubworek/unify-error-handling

Conversation

@JakubWorek

@JakubWorek JakubWorek commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Description

Error Handling Refactor and Unification

  • All error classes now form a shared, transport-agnostic hierarchy with A2AError as the base and semantic subclasses (e.g., TaskNotFoundError, RequestMalformedError). Per-transport variants (e.g., RestTaskNotFoundError, GrpcTaskNotFoundError, JsonRpcTaskNotFoundError) extend their semantic parent and carry transport-native context (HTTP status/headers/cause, gRPC status/status-details-bin, JSON-RPC envelope code/data). Type guards isRestError / isGrpcError / isJsonRpcError narrow at catch time so callers keep instanceof TaskNotFoundError and simultaneously get typed access to transport fields. Closes [Feat]: Passthrough http status code in error #317.
  • Errors live at two dedicated subpaths: @a2a-js/sdk/errors (pb-free, Workers-safe — base + semantic + REST + JSON-RPC) and @a2a-js/sdk/errors/grpc (requires @bufbuild/protobuf for grpc-status-details-bin encode/decode). The SDK root and /client / /server no longer re-export errors, so non-gRPC consumers don't pull in the pb peer dep.
  • All transport implementations (rest, grpc, json-rpc, and legacy variants) now use centralized error mapping functions from the new modules (fromRestErrorBody, fromGrpcError, fromJsonRpcErrorResponse, toRestErrorBody, toJsonRpcError, buildGrpcErrorMetadata, restStatusFor, grpcStatusFor) instead of custom or scattered logic. Adding a new error is one row in A2A_ERROR_SPECS — all wire mappings derive from it.
  • The v0.3 compat layer replaces LegacyA2AError with a thin facade over the new hierarchy that keeps the classic A2AError.taskNotFound(id) / new A2AError(code, msg, data?) API. Wire codes without a v1.0 semantic twin (PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND) are preserved via JsonRpc*Error.envelopeCode, so v0.3 clients keep seeing the same numeric codes on the wire.

Transport Implementation Simplification

  • Removed old error mapping methods from RestTransport, GrpcTransport, JsonRpcTransportHandler, and their v0.3 compat counterparts in favor of the centralized helpers, reducing code duplication and eliminating 6+ parallel error.name-keyed lookup tables.
  • Added helpers to collect HTTP headers and provide richer error context in REST transport errors.
  • Deleted src/errors.ts (354 lines) and src/server/grpc/error_details.ts (67 lines); folded into the new src/errors/ module.

Build-tests Fix

  • The existing test-build script (esbuild --platform=neutral) never actually enforced Workers-safe boundaries — platform=neutral bundles Node-only modules silently, and CI's npm ci installs devDependencies (which include @grpc/grpc-js and @bufbuild/protobuf), so the check was a no-op. Added scripts/checkWorkersSafeBundles.js that fails if any Workers-safe bundle inlines @grpc/grpc-js or @bufbuild/protobuf. TDD-verified (goes RED when errors/grpc is re-exported from the pb-free barrel, GREEN with the split).

Documentation and Migration Guide Updates

  • Updated the migration guide to explain the new error class structure, the two subpath entrypoints (@a2a-js/sdk/errors, @a2a-js/sdk/errors/grpc), and the transport-specific catch-site pattern with type guards, with code examples for the new patterns.

Closes #583 #317 🦕

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

🧪 Code Coverage

⬇️ Download Full Report

Base PR Delta
src/client/transports/grpc/grpc_transport.ts 93.42% 93.18% 🔴 -0.24%
src/client/transports/rest_transport.ts 91.57% 91.92% 🟢 +0.35%
src/compat/v0_3/client/transports/grpc/grpc_transport.ts 91.5% 91.13% 🔴 -0.37%
src/compat/v0_3/client/transports/rest_transport.ts 86.03% 86.62% 🟢 +0.59%
src/compat/v0_3/server/error.ts 75% 80.51% 🟢 +5.51%
src/compat/v0_3/server/grpc/grpc_service.ts 95.38% 95.05% 🔴 -0.33%
src/compat/v0_3/server/transports/rest/rest_transport_handler.ts 99% 99.01% 🟢 +0.01%
src/server/grpc/grpc_service.ts 82.62% 80.82% 🔴 -1.80%
src/server/transports/jsonrpc/jsonrpc_transport_handler.ts 80.95% 80% 🔴 -0.95%
src/server/transports/rest/rest_transport_handler.ts 98.97% 98.67% 🔴 -0.30%
src/errors/base.ts (new) 97.79%
src/errors/grpc/grpc.ts (new) 99.41%
src/errors/grpc/index.ts (new) 100%
src/errors/index.ts (new) 100%
src/errors/json_rpc.ts (new) 100%
src/errors/rest.ts (new) 99.34%
Total 90.7% 90.89% 🟢 +0.19%

Generated by coverage-comment.yml

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the SDK's error handling by introducing a unified, transport-agnostic error hierarchy under src/errors, with semantic subclasses and transport-specific variants (REST, gRPC, and JSON-RPC) that replace the previous monolithic and scattered error utilities. The review feedback highlights a potential server crash in src/errors/rest.ts due to an unsafe lookup in A2A_ERROR_SPECS for unregistered error names, and a semantic mismatch in the v0.3 compatibility layer where A2AError.internalError incorrectly returns a malformed request error instead of a generic JSON-RPC error.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/errors/rest.ts Outdated
Comment thread src/compat/v0_3/server/error.ts
Comment thread src/compat/v0_3/server/error.ts Outdated

@bartek-gralewicz bartek-gralewicz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be worth adding some tests that target newly added logic, like actually testing instanceof.

Comment thread src/compat/v0_3/client/transports/grpc/grpc_transport.ts Outdated
Comment thread src/index.ts Outdated
Comment thread src/errors/grpc/index.ts
@JakubWorek
JakubWorek requested a review from ishymko July 20, 2026 09:43
Comment thread .github/workflows/build-tests.yml Outdated
Comment thread package.json
Comment thread package.json Outdated
Comment thread src/errors/base.ts Outdated
Comment thread src/errors/base.ts Outdated
Comment thread src/errors/index.ts Outdated
Comment thread src/errors/base.ts
Comment thread src/errors/base.ts Outdated
Comment thread test/compat/v0_3/constants.spec.ts Outdated
@JakubWorek
JakubWorek requested a review from ishymko July 21, 2026 09:48
Comment thread .github/workflows/build-tests.yml Outdated
Comment thread src/errors/index.ts
Comment thread src/client/transports/grpc/grpc_transport.ts Outdated
Comment thread src/client/transports/grpc/grpc_transport.ts Outdated
@JakubWorek
JakubWorek merged commit 4806f8f into epic/1.0_breaking_changes Jul 22, 2026
13 checks passed
@JakubWorek
JakubWorek deleted the jakubworek/unify-error-handling branch July 22, 2026 09:15
JakubWorek added a commit that referenced this pull request Jul 22, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.0.0](v1.0.0-beta.0...v1.0.0)
(2026-07-22)

`@a2a-js/sdk` is now generally available. This release promotes the v1.0
line to stable, implementing the full [A2A Protocol Specification
v1.0](https://a2a-protocol.org/v1.0.0/specification/) across all three
transports (JSON-RPC, HTTP+JSON/REST, gRPC), with opt-in v0.3 backward
compatibility for staged migrations.

Upgrading from `0.3.x`? See the [v0.3 → v1.0 migration
guide](https://github.com/a2aproject/a2a-js/blob/v1.0.0/docs/migration-guide.md).
Interoperating with peers still on v0.3? See the [end-user v0.3
compatibility
guide](https://github.com/a2aproject/a2a-js/blob/v1.0.0/docs/compatibility-v0_3.md).


### ⚠ BREAKING CHANGES

* unify A2AError hierarchy with transport specific subclasses
([#587](#587))
* **server:** replace individual properties with SendMessageRequest in
RequestContext ([#581](#581))

### Features

* add state bag and ServerCallContextBuilder to ServerCallContext
([#364](#364))
([477e394](477e394))
* export SSE wire-format helpers from public entry point
([#548](#548))
([8bc21f5](8bc21f5)),
closes [#547](#547)
* **server:** expose SendMessageRequest metadata to AgentExecutor via
RequestContext ([#564](#564))
([a92f54e](a92f54e))
* **server:** replace individual properties with SendMessageRequest in
RequestContext ([#581](#581))
([7cd30de](7cd30de))
* unify A2AError hierarchy with transport specific subclasses
([#587](#587))
([4806f8f](4806f8f))


### Bug Fixes

* **client:** bound SSE event size to prevent client-side memory
exhaustion ([#582](#582))
([e6e8ce9](e6e8ce9))
* **client:** cancel the SSE stream on teardown to avoid leaking
connections ([#580](#580))
([83269a5](83269a5))
* **grpc:** preserve null values in protobuf Struct
([#578](#578))
([f447e4e](f447e4e)),
closes [#576](#576)
* resolve sdk compatibility bugs
([#568](#568))
([b57f026](b57f026))
* **server:** await _handleProcessingError so blocking drains surface
errors ([#579](#579))
([5833652](5833652))
* support GET for resubscribe route
([#569](#569))
([8dd43d1](8dd43d1))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: JakubWorek <jakubworek@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Unified A2AError hierarchy with transport-specific subclasses [Feat]: Passthrough http status code in error

3 participants