Skip to content

SDK doesn't validate proto REQUIRED fields in SendMessage: missing messageId, role, or parts is accepted #876

@zeroasterisk

Description

@zeroasterisk

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions