Skip to content

[Bug]: Part decoding discards a populated content key when an empty placeholder precedes it #1062

Description

@rmlopes

What happened?

What happened

JsonUtil.PartTypeAdapter.read picks the oneOf discriminator as the first content key
whose value is not JSON null. An empty string is not null, so when a producer emits
every content key of the flattened oneOf and leaves the unset ones as "", the first
empty placeholder wins and the populated key is discarded.

A DataPart sent as {"text": "", "data": {...}} decodes as an empty TextPart, and the
data payload is silently lost — no exception, no warning.

The comment directly above the scan already describes the intended behaviour:

// Find the oneOf discriminator, skipping null/empty values to tolerate formats
// where multiple content keys may be present with only one populated
// (e.g., proto serialization with alwaysPrintFieldsWithNoPresence).

Only null is skipped; "" is not. So the exact producer the comment names — proto JSON
with alwaysPrintFieldsWithNoPresence — is the one case it fails to tolerate.

Reproduction

String json = """
    {"text": "", "data": {"turns": [{"role": "user", "text": "hi"}]}}
    """;
Part<?> part = JsonUtil.OBJECT_MAPPER.fromJson(json, Part.class);
// expected: DataPart carrying the turns
// actual:   TextPart("")   — the data payload is gone

Observed against org.a2aproject.sdk:a2a-java-sdk-jsonrpc-common:

payload decodes as
{"text": "", "data": {…}} TextPart("")data lost
{"data": {…}, "text": ""} DataPart (correct)
{"text": null, "data": {…}} DataPart (correct)
{"url": "", "data": {…}} FilePartdata lost

The result depends on JSON key order, which producers are not obliged to control.

Versions

Reproduces on 1.0.0.Final and on 1.2.0.Final and current HEAD.

Expected

The first content key with a populated value should win, so that a producer emitting
empty placeholders round-trips. A part whose only content key is a deliberately empty
string ({"text": ""}) must still decode as an empty TextPart.

Impact

An agent receiving such a message answers on input the caller believes it sent. There is
no error to detect, so the failure is only visible as degraded output.

Relevant log output

Code of Conduct

  • I agree to follow this project's Code of Conduct

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