Skip to content

[Bug]: grpc_handler maps 3 A2A errors to FAILED_PRECONDITION instead of UNIMPLEMENTED, and doesn't validate A2A-Version at all #1166

Description

@avilleroy51

What happened?

grpc_handler.py's _ERROR_CODE_MAP (src/a2a/server/request_handlers/grpc_handler.py:84-98) maps 3 of the 9 A2A error types to the wrong gRPC status code, diverging from the canonical binding table in the spec (specification.md "Custom Binding Requirements" / error-code-mappings section):

A2A Error Type Spec gRPC Status SDK gRPC Status
PushNotificationNotSupportedError UNIMPLEMENTED FAILED_PRECONDITION
UnsupportedOperationError UNIMPLEMENTED FAILED_PRECONDITION
VersionNotSupportedError UNIMPLEMENTED FAILED_PRECONDITION
_ERROR_CODE_MAP: dict[type[A2AError], grpc.StatusCode] = {
    ...
    types.PushNotificationNotSupportedError: grpc.StatusCode.FAILED_PRECONDITION,
    types.UnsupportedOperationError: grpc.StatusCode.FAILED_PRECONDITION,
    ...
    types.VersionNotSupportedError: grpc.StatusCode.FAILED_PRECONDITION,
}

The other 6 mappings (TaskNotFoundError, TaskNotCancelableError, ContentTypeNotSupportedError, InvalidAgentResponseError, ExtendedAgentCardNotConfiguredError, ExtensionSupportRequiredError) are all correct against the same table.

Second, related bug: gRPC transport doesn't validate A2A-Version at all

jsonrpc_dispatcher.py and rest_dispatcher.py both guard their handlers with @validate_version(constants.PROTOCOL_VERSION_1_0), which raises VersionNotSupportedError for an unsupported A2A-Version. grpc_handler.py has no equivalent — a SendMessage gRPC call with metadata a2a-version: 99.0 is processed normally instead of being rejected. Per spec (specification.md:739): "Agents MUST process requests using the semantics of the requested A2A-Version... If the version is not supported by the interface, agents MUST return a VersionNotSupportedError."

Reproduction

Against a standard DefaultRequestHandlerV2-backed gRPC server:

import grpc
metadata = [("a2a-version", "99.0")]
client.stub.SendMessage(proto_request, metadata=metadata)
# succeeds — no VersionNotSupportedError, no version check at all

For the status-code mismatch, trigger any PushNotificationNotSupportedError (e.g. call CreatePushNotificationConfig when capabilities.push_notifications is false) over gRPC and inspect e.code() — it's FAILED_PRECONDITION, not UNIMPLEMENTED.

We hit both while running the official a2a-tck MUST-level gRPC suite against a reference SUT built on this SDK — GRPC-ERR-002 fails on test_push_not_supported_returns_unimplemented and test_version_not_supported_returns_unimplemented for exactly these reasons.

Expected

  • Fix the 3 entries in _ERROR_CODE_MAP to UNIMPLEMENTED, matching the other 6 and the spec table.
  • Apply the same version-validation the HTTP dispatchers already do to the gRPC transport (a @validate_version-equivalent, or an explicit check in GrpcHandler reading the a2a-version metadata key).

Happy to send a PR for both if useful.

Metadata

Metadata

Assignees

Labels

component: serverIssues related to frameworks for agent execution, HTTP/event handling, database persistence logic.status:awaiting response

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions