a2aproject / a2aproject/a2a-java

[Bug]: SSE client rejects any event whose data arrives on a single line over 64KB, with no way to configure the limit

Đang mở
#1,123 1 bình luận 1 reaction 1 người được giao Được @ehsavoie nhận Xem trên GitHub
Ngôn ngữ chính
Java
Star
490
Fork
172
Merge trung bình
1 ngày 6 giờ
Pull request đã merge (30 ngày)
55

Mô tả

### What happened?

`ServerSentEventParser` enforces a hard-coded 64 KB limit on a single SSE line. Any A2A server that
serializes an event as one `data:` field larger than that is unreadable by the Java client, and there
is no way for an application to raise, lower or disable the limit.

We hit this against a production agent whose final `TaskArtifactUpdateEvent` carries a large result
artifact. The stream opens, runs, and then dies mid-flight:

java.lang.IllegalArgumentException: Line exceeds maximum length of 65536 characters
at org.a2aproject.sdk.client.http.ServerSentEventParser.processLine(ServerSentEventParser.java:58)

**Why we think this is a bug rather than intended hardening**

1. Neither the [SSE specification]
nor the A2A specification places any limit on line length, so a server emitting a 200 KB `data:`
line is fully conformant. The Java client is the only participant that rejects it.

2. The limit is inconsistent with the parser's own per-event budget. `MAX_BUFFER_CHARS` allows 1 MB
of data spread across up to `MAX_BUFFER_SIZE` = 1000 lines. So the *same* 200 KB payload is
accepted when the server splits it across several `data:` lines and rejected when it sends one.
The DoS exposure is identical either way — the parser buffers the same total — so the per-line cap
costs interoperability without buying protection the per-event caps do not already provide.

3. It is not interoperable with the other A2A SDKs. The Python SDK reads streams with `httpx-sse`,
which accumulates `data:` lines until a blank line and imposes no per-line ceiling. A server that
every Python client reads happily is unreadable from Java. In our case the producer is
`a2a-sdk==1.1.0` (Python) serving through `sse-starlette`, which emits `json.dumps(...)` as a
single `data:` field because compact JSON contains no newlines — so this is the default framing of
the reference Python server, not an unusual choice.

**What we expected**

Either of:

- the per-line limit to be configurable (constructor parameter, builder option, or system property),
alongside the existing buffer limits; or
- the per-line limit to be removed, leaving `MAX_BUFFER_CHARS` / `MAX_BUFFER_SIZE` as the DoS bound,
since they already cap total memory per event.

Making all three configurable together would be ideal — 1 MB per event is also reachable for agents
returning large artifacts.

**Minimal reproducer**

String hugeJson = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"" + "x".repeat(70_000) + "\"}";

List events = new ArrayList<>();
List errors = new ArrayList<>();
ServerSentEventParser parser = new ServerSentEventParser(events::add, errors::add);

parser.processLine("data: " + hugeJson);
parser.processLine("");

// events is empty; errors holds IllegalArgumentException("Line exceeds maximum length of 65536 characters")
// Splitting the same payload across two `data:` lines parses fine.

**Environment**

- `a2a-java-sdk-client` / `a2a-java-sdk-http-client` `1.1.0.Final`, JDK transport
(`JdkA2AHttpClient`), JSON-RPC transport binding
- Also present unchanged in `v1.3.0.Final` and on `main` at time of writing
- Server: Python `a2a-sdk` 1.1.0 behind `sse-starlette` 3.4.6

**Source**

`http-client/src/main/java/org/a2aproject/sdk/client/http/ServerSentEventParser.java`

private static final int MAX_BUFFER_SIZE = 1000;
private static final int MAX_BUFFER_CHARS = 1024 * 1024; // 1 MB
private static final int MAX_LINE_LENGTH = 65536; // 64 KB

public void processLine(@Nullable String line) {
...
if (line.length() > MAX_LINE_LENGTH) {
handleError(new IllegalArgumentException("Line exceeds maximum length of " + MAX_LINE_LENGTH + " characters"));
skippingCurrentEvent = true;

Because `ServerSentEventParser` is shared across the HTTP client implementations, this affects every
transport that streams over SSE, not just the JDK one.

### Relevant log output

```shell
2026-09-01 11:30:35 WARN Downstream A2A call failed: method=SendStreamingMessage, rpcId=g-bdf28358-f7e1-41c1-91e1-417005473594,
url=http://localhost...:8000,
message=Line exceeds maximum length of 65536 characters
java.lang.IllegalArgumentException: Line exceeds maximum length of 65536 characters
at org.a2aproject.sdk.client.http.ServerSentEventParser.processLine(ServerSentEventParser.java:58)
```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.