[Bug]: SSE client splits data lines on U+2028, U+2029 and U+0085, so streamed events fail to parse
Los mantenedores suelen responder en 2 días
Evaluación
Este issue todavía no se ha evaluado.
Descripción
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.
- Lenguaje dominante
- Python
- Estrellas
- 2.2k
- Forks
- 532
- Merge medio
- 3 d 2 h
- PR fusionados (30 d)
- 46
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de a2aproject/a2a-python
-
[Bug]: `A2A-Version` validation ignores minor versions and the query parameterPosiblemente ocupada @rohityan la tomó hace 74 días. Abiertocomponent: server status:awaiting response status:stale
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
a2aproject/a2a-python#1204 · 4 comentarios · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
[Bug]: REST task/request id sanitizationPosiblemente ocupada @Linux2010 la tomó hace 133 días. Abiertomaintainers-only
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
a2aproject/a2a-python#805 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
v0.3 REST and gRPC clients send blocking requests as non-blockingPosiblemente ocupada @ConnorMoss02 la tomó hace 1 día. Abiertocomponent: client
a2aproject/a2a-python#1428 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
Compat REST client drops security from the v0.3 extended agent cardPosiblemente ocupada @ConnorMoss02 la tomó hace 3 días. Abiertocomponent: client status:awaiting response
a2aproject/a2a-python#1418 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
[Feat]: Add a task-state-invariants agent skill for sibling-surface propagationPosiblemente ocupada @Linux2010 la tomó hace 5 días. Abiertocomponent: tooling status:awaiting response
a2aproject/a2a-python#1413 · 3 comentarios · 1 asignado ·
Los mantenedores suelen responder en 2 días
Todos los issues de a2aproject/a2a-python
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
NVIDIA/auto-ontology#463 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
NousResearch/hermes-agent#151165 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 1 día
-
code-health
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
tinaudio/synth-setter#3750 ·
Los mantenedores suelen responder en 1 día
-
[Bug] vllm-sr config migrate drops providers.models[].deploymentPosiblemente ocupada @Bevisy la tomó hoy. Abiertoneeds-acceptance wg/developer-experience-ecosystem
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
vllm-project/semantic-router#5996 ·
Los mantenedores suelen responder en 2 días