-
Notifications
You must be signed in to change notification settings - Fork 395
Description
Summary
The v1.0 Python SDK does not validate that REQUIRED proto fields are present when processing SendMessage JSON-RPC requests. A message without messageId, role, or parts is silently accepted and processed instead of returning InvalidParamsError (-32602).
Spec Reference
A2A v1.0 specification/a2a.proto — Message definition:
message Message {
string message_id = 1 [(google.api.field_behavior) = REQUIRED];
string context_id = 2;
string task_id = 3;
Role role = 4 [(google.api.field_behavior) = REQUIRED];
repeated Part parts = 5 [(google.api.field_behavior) = REQUIRED];
google.protobuf.Struct metadata = 6;
repeated string extensions = 7;
repeated string reference_task_ids = 8;
}All three of message_id, role, and parts are marked REQUIRED. A server receiving a message missing any of these MUST return an error per proto field_behavior semantics.
Reproduction
Against any v1.0 SDK agent:
# Missing messageId:
curl -X POST http://localhost:9997 -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"SendMessage","params":{"message":{"role":"ROLE_USER","parts":[{"text":"no id"}]}},"id":"1"}'
# ACTUAL: {"result": {"task": {...}}} ← SUCCESS (should be error)
# EXPECTED: {"error": {"code": -32602, "message": "Missing required field: messageId"}}
# Missing role:
curl -X POST http://localhost:9997 -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"SendMessage","params":{"message":{"messageId":"msg-1","parts":[{"text":"no role"}]}},"id":"1"}'
# ACTUAL: {"result": {"task": {...}}} ← SUCCESS (should be error)
# Missing parts:
curl -X POST http://localhost:9997 -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"SendMessage","params":{"message":{"messageId":"msg-1","role":"ROLE_USER"}},"id":"1"}'
# ACTUAL: {"result": {"task": {...}}} ← SUCCESS (should be error)Root Cause
In proto3 JSON deserialization, missing fields are silently treated as the zero/default value:
- Missing
message_id→ empty string"" - Missing
role→ROLE_UNSPECIFIED (0) - Missing
parts→ empty list[]
The SDK (via google.protobuf.json_format.ParseDict) does not honor google.api.field_behavior = REQUIRED as a validation constraint during deserialization.
Affected code: a2a/server/apps/jsonrpc/jsonrpc_app.py — _decode_request() or the calling handler should validate required fields.
Expected Fix
Add a validation step after proto deserialization that checks for empty/zero-value REQUIRED fields:
def _validate_message(message: Message) -> None:
if not message.message_id:
raise InvalidParamsError(message='messageId is required')
if message.role == Role.ROLE_UNSPECIFIED:
raise InvalidParamsError(message='role is required')
if not message.parts:
raise InvalidParamsError(message='parts is required')Impact
- TCK test
test_missing_required_message_fields(optional/features) fails for all v1.0 SDK agents - Agents may process malformed messages and produce undefined behavior
- Protocol compliance gap: agents are supposed to reject invalid messages
Context
Discovered during A2A TCK Round 2 gap analysis. This is distinct from #872 (ListTasks pagination). The SDK version tested is a2a-sdk==1.0.0a0.