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

Abierto
#1,166 4 comentarios 0 reacciones 1 asignado Reclamado por @avilleroy51 Ver en GitHub
component: server status:awaiting response status:stale
Lenguaje dominante
Python
Estrellas
2.1k
Forks
496
Merge medio
4 d 17 h
PR fusionados (30 d)
12

Descripción

### 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.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.