Whole numbers in a data Part are returned as floats (e.g. 4326 becomes 4326.0)
Maintainer thường phản hồi trong vòng 2 ngày
@rohityan đang làm issue này rồi.
Từ ngày 9/10/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Summary
When an agent sends structured data in a data Part, every whole number in that
data comes back to the client as a decimal number. For example, the integer
4326 is received as 4326.0.
This happens on the normal REST + JSON transport (the response body is JSON over
HTTPS, not gRPC). A client that expects a whole number for a field therefore
receives a decimal and may reject the message during validation.
I believe this is a side effect of how the SDK builds the JSON, not something the
A2A specification requires. I am filing it so it is written down in one place for
both maintainers and other developers who hit the same thing.
What I expected
If my agent puts the whole number 4326 into a data Part, the client should
receive 4326 (a whole number), the same value I put in.
What actually happens
The client receives 4326.0 (a decimal). This is true for every whole number
in the structured data, not just one field. In my case the same response also
turned 240 into 240.0, 500 into 500.0, and 48000000 into 48000000.0.
Why it happens (as far as I can tell)
Since the 1.0 release the SDK represents every message as a Protocol Buffers
object in memory. The data field of a Part is typed as a protobuf Struct
value:
# a2a/types/a2a_pb2.pyi
data: _struct_pb2.Value
A protobuf Struct has only one way to store a number: number_value, which is
a 64-bit floating-point number (a double). It has no separate type for whole
numbers. So the moment a whole number is placed into a Struct, it becomes a
decimal.
When the SDK produces the JSON response, it converts that protobuf object with
MessageToDict (and the streaming path yields MessageToDict per frame):
# a2a/server/routes/rest_dispatcher.py
from google.protobuf.json_format import MessageToDict, Parse
...
return A2AJSONResponse(content=MessageToDict(response)) # non-streaming
...
yield MessageToDict(response) # each SSE frame
MessageToDict faithfully copies the number out of the Struct — but by then it
is already a decimal, so the JSON shows 4326.0.
So the number is lost on the way in (when it is stored in the Struct), not
on the way out. The REST + JSON transport is not the cause; the cause is the
in-memory Struct typing that sits behind it.
Minimal reproduction
No server needed — this reproduces with the protobuf tools the SDK uses:
from google.protobuf import struct_pb2
from google.protobuf.json_format import ParseDict, MessageToDict
v = struct_pb2.Value()
ParseDict({"spatialReference": 4326, "assetEmployees": 240}, v)
print(MessageToDict(v))
# -> {'spatialReference': 4326.0, 'assetEmployees': 240.0}
The whole numbers go in and come out as decimals.
Environment
a2a-sdkversion:1.2.1(also present in1.2.2; unchanged by that patch)- Transport: REST + JSON over HTTPS, server built with
create_rest_routes/
RestDispatcher/DefaultRequestHandlerV2 - Python 3.13
Is this a specification violation?
I do not think it is, and I want to be fair about that. The A2A data Part holds
general structured JSON, and plain JSON does not separate whole numbers from
decimals — 4326 and 4326.0 are the same JSON number. So a strict reading of
the spec is satisfied.
The problem is practical, not formal: many real clients and schemas do treat
whole numbers and decimals as different types (for example, an identifier field
typed as an integer). For those clients, receiving 4326.0 where they modelled
4326 is a validation failure. This is a loss of fidelity — the value you sent
is not the value shape the receiver gets back — introduced by the move to
protobuf types, even though no rule is technically broken.
This is closely related to #884 (the removal of Pydantic models and the resulting
rough edges of the proto-only path). This is one concrete, user-visible symptom of
that.
Suggested resolution (small and spec-safe)
I am not asking you to change the wire format or break the spec. Either of these
would help:
- Document it clearly. State in the docs that whole numbers in a
dataPart
are delivered as decimals, so client authors expect it and coerce on their side.
This alone would have saved me a long investigation. - Offer an opt-in way to keep whole numbers whole. For example, a
serialization helper or flag that narrows decimals with no fractional part back
to whole numbers when producing the JSON. Opt-in, so nothing changes for anyone
who does not ask for it.
Workaround for anyone else who finds this
Until the above exists, fix it on the client: when you expect a whole number
for a field, accept a decimal whose fractional part is zero and convert it back to
a whole number (reject only genuinely fractional values). Scope this to fields
that are meant to be whole numbers — do not blanket-convert, or you will corrupt
values that are legitimately decimals (coordinates, distances, measurements).
- Ngôn ngữ chính
- Python
- Star
- 2.2k
- Fork
- 509
- Merge trung bình
- 3 ngày 11 giờ
- Pull request đã merge (30 ngày)
- 43
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của a2aproject/a2a-python
-
[Bug]: REST task/request id sanitizationCó thể đã có người làm @Linux2010 đã nhận 106 ngày trước. Đang mởmaintainers-only
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
a2aproject/a2a-python#805 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[Bug]: Agent card signature verification raises raw binascii.Error on a malformed protected header instead of SignatureVerificationErrorCó thể đã có người làm @rohityan đã nhận 2 ngày trước. Đang mở
a2aproject/a2a-python#1332 · 2 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[Bug]: Framework-written FAILED status drops status.timestamp, persisting last_updated as NULLCó thể đã có người làm @rohityan đã nhận 2 ngày trước. Đang mở
a2aproject/a2a-python#1331 · 2 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[Bug]: message/send hangs forever when the AgentExecutor returns without producing eventsCó thể đã có người làm @rohityan đã nhận 2 ngày trước. Đang mở
a2aproject/a2a-python#1330 · 2 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[Feat]: Cluster mode: detect and recover tasks abandoned by a crashed replica (heartbeat/lease)Có thể đã có người làm @ishymko đã nhận 2 ngày trước. Đang mởcomponent: server status: needs review
a2aproject/a2a-python#1324 · 4 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của a2aproject/a2a-python
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
vllm-project/vllm#61131 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
kubernetes-client/python#2735 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
desktop help wanted test
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Broken links found in docsĐang mởdocs pydanty:is-working
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
pydantic/pydantic-ai#10113 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Tutorial unit test leaks sample data into tutorial doctestCó thể đã có người làm @Gambit-Checkmate đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100