Skip to content

feat: implement rich gRPC error details per A2A v1.0 spec#790

Open
knapg wants to merge 1 commit into1.0-devfrom
knap/gRPC-Errors-Status
Open

feat: implement rich gRPC error details per A2A v1.0 spec#790
knapg wants to merge 1 commit into1.0-devfrom
knap/gRPC-Errors-Status

Conversation

@knapg
Copy link
Collaborator

@knapg knapg commented Mar 9, 2026

Description

This PR implements standard gRPC rich error handling using google.rpc.Status and google.rpc.ErrorInfo, bringing the SDK's gRPC transport fully in line with the A2A v1.0 specification.

Previously, the gRPC server appended the exception name to the string message (e.g., "TaskNotFoundError: task not found"), and the client relied on string splitting to parse the error back into a domain exception. This approach was brittle and not interoperable with standard gRPC ecosystems (proxies, gateways, etc.).

This PR replaces the string-parsing heuristic with strongly-typed binary metadata (grpc-status-details-bin), while retaining backward compatibility for clients talking to older A2A v0.3 servers.

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests and linter pass (Run bash scripts/format.sh from the repository root to format)
  • Appropriate docs were updated (if necessary)

Fixes #723 🦕

@knapg knapg requested a review from ishymko March 9, 2026 12:50
@knapg knapg requested a review from a team as a code owner March 9, 2026 12:50
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the gRPC error handling within the A2A SDK by adopting a standardized, robust mechanism. It transitions from a fragile string-based error parsing approach to using strongly-typed binary metadata, which greatly improves the reliability and interoperability of error communication across the gRPC ecosystem. This change ensures compliance with the A2A v1.0 specification while carefully preserving compatibility with previous protocol versions.

Highlights

  • Rich gRPC Error Handling: Implemented standard gRPC rich error handling using google.rpc.Status and google.rpc.ErrorInfo to align with the A2A v1.0 specification.
  • Improved Error Parsing: Replaced the brittle string-parsing heuristic for errors with strongly-typed binary metadata (grpc-status-details-bin), enhancing interoperability and reliability.
  • Backward Compatibility: Ensured backward compatibility for clients communicating with older A2A v0.3 servers by maintaining a fallback to legacy string-based error parsing.
  • New Error Types: Introduced ExtensionSupportRequiredError and VersionNotSupportedError to provide more specific error contexts.
  • Server-Side Error Serialization: Modified the gRPC server to serialize rich error details into grpc-status-details-bin trailing metadata when an A2A error occurs.
  • Client-Side Error Deserialization: Updated the gRPC client to parse rich error details from grpc-status-details-bin metadata, falling back to the legacy string format if the rich details are not present.
Changelog
  • src/a2a/client/transports/grpc.py
    • Added imports for google.rpc protobufs (error_details_pb2, status_pb2) and A2A error types.
    • Introduced _parse_rich_grpc_error to deserialize and interpret grpc-status-details-bin metadata.
    • Modified _map_grpc_error to prioritize parsing rich error details from metadata, with a fallback to legacy string parsing.
  • src/a2a/server/request_handlers/grpc_handler.py
    • Added imports for google.protobuf.any_pb2 and google.rpc protobufs.
    • Modified abort_context to construct google.rpc.Status and google.rpc.ErrorInfo objects.
    • Serialized rich error details into grpc-status-details-bin trailing metadata.
    • Updated the message passed to context.abort to use the status.message instead of the ExceptionName: message format.
    • Imported A2A_ERROR_REASONS for error mapping.
  • src/a2a/utils/errors.py
    • Defined new exception classes: ExtensionSupportRequiredError and VersionNotSupportedError.
    • Created A2A_ERROR_REASONS dictionary mapping A2A error classes to string reasons.
    • Created A2A_REASON_TO_ERROR dictionary for reverse lookup.
    • Added new error classes and mappings to __all__.
  • tests/client/transports/test_grpc_client.py
    • Added imports for google.protobuf.any_pb2, google.rpc.error_details_pb2, google.rpc.status_pb2.
    • Renamed test_grpc_mapped_errors to test_grpc_mapped_errors_legacy to clarify its purpose.
    • Added test_grpc_mapped_errors_rich to specifically test the new rich error handling mechanism.
    • Imported A2A_ERROR_REASONS for test setup.
  • tests/server/request_handlers/test_grpc_handler.py
    • Added imports for google.rpc.error_details_pb2, google.rpc.status_pb2.
    • Modified existing error handling tests to reflect the change in abort message format (removed ExceptionName: prefix).
    • Added test_abort_context_rich_error_format to verify the correct serialization of rich error details into metadata.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@knapg knapg force-pushed the knap/gRPC-Errors-Status branch from 0562163 to acc32c2 Compare March 9, 2026 13:04
Copy link
Contributor

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

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 successfully implements rich gRPC error handling as per the A2A v1.0 specification, which is a great improvement for interoperability and robustness. However, the implementation of the abort_context function on the server side contains critical bugs (TypeError and AttributeError) that will cause the request handler to crash whenever an error occurs, leading to a denial of service for those requests. Additionally, metadata decoding lacks error handling for invalid UTF-8 sequences, which could also be exploited for a minor denial of service. While the overall changes are clean, well-structured, and include comprehensive tests, these critical security issues must be addressed to ensure the SDK fails securely and gracefully. There is also a minor suggestion to improve an existing test.

@knapg knapg force-pushed the knap/gRPC-Errors-Status branch from acc32c2 to fdb156b Compare March 9, 2026 13:12
Comment on lines +143 to +146
InvalidParamsError: 'INVALID_PARAMS',
InvalidRequestError: 'INVALID_REQUEST',
MethodNotFoundError: 'METHOD_NOT_FOUND',
InternalError: 'INTERNAL_ERROR',
Copy link
Member

Choose a reason for hiding this comment

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

I believe those are JSON-RPC leftovers, we can keep A2A errors only here: https://a2a-protocol.org/latest/specification/#54-error-code-mappings.

}


def _parse_rich_grpc_error(
Copy link
Member

Choose a reason for hiding this comment

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

"""Sets the grpc errors appropriately in the context."""
code = _ERROR_CODE_MAP.get(type(error))

status_value = code.value if code else grpc.StatusCode.UNKNOWN.value
Copy link
Member

Choose a reason for hiding this comment

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

Comment on lines 98 to 103
if isinstance(details, str) and ': ' in details:
error_type_name, error_message = details.split(': ', 1)
# TODO(#723): Resolving imports by name is temporary until proper error handling structure is added in #723.
# Leaving as fallback for errors that don't use the rich error details.
exception_cls = _A2A_ERROR_NAME_TO_CLS.get(error_type_name)
if exception_cls:
raise exception_cls(error_message) from e
Copy link
Member

Choose a reason for hiding this comment

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

This code was added in 1.0-dev branch and was never released (#761). It is safe to remove it.

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.

2 participants