[Bug]: SSE client splits data lines on U+2028, U+2029 and U+0085, so streamed events fail to parse
维护者通常 2 天内回复
评估
这个 Issue 还没有评估数据。
描述
What happened?
parse_sse_stream in src/a2a/client/transports/http_helpers.py reads the stream with response.aiter_lines() (line 78). httpx's line decoder follows str.splitlines(), so it also ends a line at U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR) and U+0085 (NEL). SSE line ends are only CR, LF and CRLF, and the docstring on line 73 says the parser conforms to the SSE spec.
The server writes these three characters raw: json_utils.dumps uses ensure_ascii=False (src/a2a/utils/json_utils.py:19). sse-starlette frames on CR/LF only, so it sends one data: line. The client splits that line into several. json.loads fails on the first piece, and the stream ends with A2AClientError('Invalid JSON-RPC response in SSE stream').
Any string field in a streamed event can hold these characters, for example message text, artifacts or status messages that quote a document. Resubscribing sends the same task snapshot, so that task stays unreadable over streaming. Non-streaming GetTask is not affected. The same parser is used by the JSON-RPC and REST transports and by the v0.3 compat transports.
This looks like a regression from #1132, which removed httpx-sse. httpx-sse 0.4.3 split SSE lines on CR/LF only (_splitlines_sse).
Repro (library level, using the versions pinned in uv.lock: sse-starlette 3.4.4, httpx 0.28.1)
import asyncio, json
import httpx
from sse_starlette.sse import ServerSentEvent
async def main():
data = json.dumps({"text": "before
after"}, ensure_ascii=False)
frame = ServerSentEvent(data=data).encode()
print(frame.count(b"data:")) # 1: the server sends one data line
async def body():
yield frame
resp = httpx.Response(200, content=body())
lines = [l async for l in resp.aiter_lines()]
print(len(lines)) # 3: the client sees the data line split in two
json.loads(lines[0][len("data: "):])
asyncio.run(main())
Expected: one data: line that parses as JSON. Observed: JSONDecodeError.
Possible fixes:
- Split SSE lines on CR, LF and CRLF only, with a small line decoder over
aiter_text(). - Also, or instead: escape U+2028, U+2029 and U+0085 in
json_utils.dumps.
Related: #1213, the end-of-stream flush in the same parser.
No existing tests cover these characters in SSE data.
Relevant log output
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 10 (char 9)
Code of Conduct
- I agree to follow this project's Code of Conduct
Drafted with Claude Code. I reviewed the code paths and ran the repro.
- 主要语言
- Python
- 星标
- 2.2k
- 派生
- 532
- 平均合并
- 3 天 2 小时
- 30 天内合并 PR
- 46
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
a2aproject/a2a-python 的其他 Issue
-
[Bug]: `A2A-Version` validation ignores minor versions and the query parameter可能已有人在做 @rohityan 于 74 天前认领。 未关闭component: server status:awaiting response status:stale
难度 2/5 1-3 小时 新手友好度 75/100
a2aproject/a2a-python#1204 · 4 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
-
[Bug]: REST task/request id sanitization可能已有人在做 @Linux2010 于 133 天前认领。 未关闭maintainers-only
难度 2/5 1-3 小时 新手友好度 65/100
a2aproject/a2a-python#805 · 1 条评论 ·
维护者通常 2 天内回复
-
v0.3 REST and gRPC clients send blocking requests as non-blocking可能已有人在做 @ConnorMoss02 于 1 天前认领。 未关闭component: client
a2aproject/a2a-python#1428 · 1 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
-
Compat REST client drops security from the v0.3 extended agent card可能已有人在做 @ConnorMoss02 于 3 天前认领。 未关闭component: client status:awaiting response
a2aproject/a2a-python#1418 · 1 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
-
[Feat]: Add a task-state-invariants agent skill for sibling-surface propagation可能已有人在做 @Linux2010 于 5 天前认领。 未关闭component: tooling status:awaiting response
a2aproject/a2a-python#1413 · 3 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
查看 a2aproject/a2a-python 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 84/100
NVIDIA/auto-ontology#463 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 86/100
NousResearch/hermes-agent#151165 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 66/100
维护者通常 1 天内回复
-
code-health
难度 2/5 1-3 小时 新手友好度 78/100
tinaudio/synth-setter#3750 ·
维护者通常 1 天内回复
-
[Bug] vllm-sr config migrate drops providers.models[].deployment可能已有人在做 @Bevisy 今天认领。 未关闭needs-acceptance wg/developer-experience-ecosystem
难度 2/5 1-3 小时 新手友好度 86/100
vllm-project/semantic-router#5996 ·
维护者通常 2 天内回复