a2aproject / a2aproject/a2a-python
[Bug]: grpc_handler maps 3 A2A errors to FAILED_PRECONDITION instead of UNIMPLEMENTED, and doesn't validate A2A-Version at all
- 主要語言
- Python
- 星號
- 2.1k
- 分支
- 496
- 平均合併
- 4 天 17 小時
- 30 天內合併 PR
- 12
描述
### 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` ❌ |
```python
_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:
```python
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.
貢獻指南
評估
這個 Issue 還沒有評估資料。