NetworkTransport drops a JSON message when a TCP receive contains a heartbeat followed by the message

Abierto
#322 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 2 días

@bbdu3 ya está trabajando en esto.

Desde el 6/11/2026.

  • #323 de @bbdu3 — abierto

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
25/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Estancado
Stack tecnológico
swift
Área
networking

Línea de trabajo

Read NetworkTransport.receiveLoop() and the heartbeat framing logic to see how received bytes are buffered and consumed. Then inspect the transport tests for a way to deliver multiple frames in one chunk; done means a heartbeat followed by a JSON-RPC response and a later response are both delivered in order. A linked open pull request is already addressing this issue.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

NetworkTransport.receiveLoop() skips an entire received data chunk when Heartbeat.isHeartbeat(newData) returns true. This check only examines the first four bytes, so a chunk containing a heartbeat followed by a JSON-RPC message is treated entirely as a heartbeat.

How to trigger

The sender writes a 12-byte heartbeat, followed by a newline-delimited JSON-RPC message. TCP can deliver these two writes together in one receive callback:

[heartbeat][{"jsonrpc":"2.0","id":1,"result":{}}\n]

The receiver recognizes the heartbeat prefix and executes continue before reaching buffer.append(newData). The JSON-RPC message following the heartbeat is therefore discarded.

I validated this using a Python model of the relevant receive-loop logic, with a second response as a marker:

Separate chunks: heartbeat, response 1, response 2
Delivered response IDs: [1, 2]

Combined chunk: heartbeat + response 1, followed by response 2
Delivered response IDs: [2]

I also tested two separate writes over Linux TCP loopback. In 20 trials, the heartbeat and first response arrived together in one recv() call, with all bytes intact.

These checks establish that the input arrangement can occur over TCP and that the modeled receive logic drops the trailing message. I have not run the Swift SDK or Network.framework on macOS.

Impact

A JSON-RPC message following a heartbeat in the same receive chunk is not delivered through the transport’s receive stream. If it is a response, its pending request can remain unresolved until cancellation, disconnection, or an application-level timeout.

This report is limited to TCP and the case of a complete heartbeat followed by a complete JSON-RPC message in one receive callback.

my fix thought

The receiver should parse frames from buffered bytes instead of treating each receive callback as a complete application message. After identifying a complete heartbeat, it should consume only those 12 bytes and continue processing any remaining bytes.

A regression test could queue heartbeat + response 1 as one chunk, then response 2 as another, and assert that both responses are delivered in order. The same assertion should pass when the heartbeat and responses arrive separately.

If my repair strategy is right, I will open a PR to fix it.

Lenguaje dominante
Swift
Estrellas
1.6k
Forks
270
Merge medio
2 d 7 h
PR fusionados (30 d)
15

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de modelcontextprotocol/swift-sdk

Todos los issues de modelcontextprotocol/swift-sdk

Issues similares

Más issues de Swift

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.