[Bug]: REST transport: getTask builds an invalid URL for single-digit historyLength
メンテナーはふだん 1 日以内に返信
@014-code がすでに取り組んでいます。
2026年10月2日 から。
評価
調査の方向性
client/transport/rest/src/main/java/io/a2aproject/a2a/client/transport/rest/RestTransport.java の getTask から始めて、URL のフォーマットを確認します。historyLength が 5 のような 1 桁の値になる場合に RestTransportTest.testGetTask を実行し、生成された URI が有効で、クエリにパディングがないことを示す回帰テストのカバレッジを追加します。関連するフォーマット文字列が変更に含まれる場合は、それらを正規化します。
索引モデルが issue の本文から書いたものです。
説明
What happened?
Summary
RestTransport.getTask builds the request URL with a String.format pattern that uses width specifiers (%2d) where argument-index specifiers (%2$d) were intended. For a single-digit historyLength (0–9), %2d left-pads the value with a space, producing historyLength= 5. A raw space is illegal in a URI, so java.net.URI.create(...) throws IllegalArgumentException: Illegal character in query, and the getTask call fails before any request is sent.
Affected code
client/transport/rest/src/main/java/io/a2a/client/transport/rest/RestTransport.java, in getTask:
url.append(String.format("/tasks/%1s?historyLength=%2d", taskQueryParams.id(), taskQueryParams.historyLength()));
In Java format syntax, an argument index requires a trailing $ (%2$d). Without it, %2d means "decimal, minimum width 2", and %1s means "string, minimum width 1" — these are width fields, not argument references. The %1s on the id is harmless only by accident (a UUID is always wider than 1, so nothing is padded); the %2d on the integer pads any single-digit value.
Reproduction
String.format("/tasks/%1s?historyLength=%2d", "de38c76d-d54c-436c-8b9f-4c2703648d64", 5);
// => "/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64?historyLength= 5"
// ^ stray space
URI.create("https://host/tasks/de38c76d-d54c-436c-8b9f-4c2703648d64?historyLength= 5");
// => java.lang.IllegalArgumentException: Illegal character in query at index N: ...historyLength= 5
Behavior by value:
| historyLength | formatted query | valid URI? |
|---|---|---|
| 1–9 | historyLength= N (leading space) |
❌ |
| 0 | n/a — getTask skips the query when historyLength <= 0 |
✅ |
| ≥ 10 | historyLength=NN |
✅ |
So any getTask call with historyLength in 1–9 fails. This is the common case (clients typically request a small history window), which makes the practical impact high.
Why existing tests don't catch it
RestTransportTest.testGetTask uses new TaskQueryParams("...", 10) — a two-digit value that satisfies the width-2 field, so no space is injected and the URL stays valid. Single-digit values are never exercised.
Suggested fix
Drop the width (preferred) or use real positional indices:
// simplest
url.append(String.format("/tasks/%s?historyLength=%d", taskQueryParams.id(), taskQueryParams.historyLength()));
// or, if explicit indices are desired
url.append(String.format("/tasks/%1$s?historyLength=%2$d", taskQueryParams.id(), taskQueryParams.historyLength()));
Also recommend adding a regression test that calls getTask with a single-digit historyLength (e.g. 5) and asserts the resulting URL/query is well-formed.
Related occurrences (same specifier mistake, latent)
The same %Ns width-vs-index pattern appears on other URL-building sites in RestTransport.java (e.g. /tasks/%1s:cancel, /tasks/%1s/pushNotificationConfigs/%2s, /tasks/%1s:subscribe). These don't currently misbehave because their arguments are strings whose length exceeds the width, so no padding occurs — but they're the same bug waiting on a short/empty value and would be worth normalizing to %s in the same change.
Environment
- Observed on the v1.x line (
org.a2aproject.sdk) and the v0.3 line (io.github.a2asdk:0.3.3.Final); both contain the identicalhistoryLength=%2dline, and it is still present on the latestmain. - Transport: HTTP+JSON (REST). JSON-RPC transport is unaffected (it doesn't build this query).
Relevant log output
Code of Conduct
- I agree to follow this project's Code of Conduct
- 主要言語
- Java
- スター
- 505
- フォーク
- 185
- 平均マージ
- 1日 9時間
- マージ済み PR(30日)
- 25
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
a2aproject/a2a-java のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
a2aproject/a2a-java#1012 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
a2aproject/a2a-java#464 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Create a sample that demonstrates how to use a shared contextId across multiple tasks再び着手できるかも @tanish111 が 356 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンsample
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
a2aproject/a2a-java#375 · コメント 5 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 28/100
a2aproject/a2a-java#1211 ·
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
a2aproject/a2a-java#1207 ·
メンテナーはふだん 1 日以内に返信
a2aproject/a2a-java の issue をすべて見る
似ている issue
-
Flight SQL JDBC parses boolean properties case-sensitively, silently disabling TLS for useEncryption=TRUE対応中かも @Arawoof06 が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
apache/arrow-java#1357 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
apache/rocketmq-dashboard#6610 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
MetricsHub/metricshub-community#1396 ·
メンテナーはふだん 1 日以内に返信
-
L: java:gradle L: java:maven L: ruby:bundler T: bug 🐞
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
dependabot/dependabot-core#16547 ·
メンテナーはふだん 1 日以内に返信
-
Citationcount column sorts alphabetically instead of numerically対応中かも @kpunia306 が今日担当しました。 オープンstatus: needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
JabRef/jabref#17459 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信