can1357/oh-my-pi · error · RpcError
RPC chunk sequence was interrupted
Error message
RPC chunk sequence was interrupted
What it means
_RpcFrameDecoder.push() reassembles multi-frame `rpc_chunk` sequences. Once a chunk sequence is pending, the very next frame must be another `rpc_chunk` of the same chunkId; if any non-chunk frame (or non-dict value) arrives first, it raises RpcError("RPC chunk sequence was interrupted"). This preserves protocol integrity — a large RPC response whose chunks were interleaved with or truncated by other frames cannot be reassembled safely.
Source
Thrown at python/omp-rpc/src/omp_rpc/client.py:144
@dataclass(slots=True)
class _PendingRpcChunks:
chunk_id: str
count: int
byte_length: int
next_index: int = 0
chunks: list[bytes] = field(default_factory=list)
received_bytes: int = 0
class _RpcFrameDecoder:
def __init__(self) -> None:
self._pending: _PendingRpcChunks | None = None
def push(self, value: object) -> JsonObject | None:
if not isinstance(value, dict) or value.get("type") != "rpc_chunk":
if self._pending is not None:
raise RpcError("RPC chunk sequence was interrupted")
if not isinstance(value, dict):
raise RpcError("RPC frame must be a JSON object")
return cast(JsonObject, value)
chunk_id = value.get("chunkId")
index = value.get("index")
count = value.get("count")
byte_length = value.get("byteLength")
data = value.get("data")
max_chunk_count = (
_MAX_RPC_REASSEMBLED_BYTES + _RPC_CHUNK_PAYLOAD_BYTES - 1
) // _RPC_CHUNK_PAYLOAD_BYTES
if (
not isinstance(chunk_id, str)
or not chunk_id
or len(chunk_id) > 128
or not isinstance(index, int)
or isinstance(index, bool)View on GitHub (pinned to 9690622007)
Solutions
- Ensure the peer emits all chunks of a chunkId contiguously (same chunkId, indices 0..count-1) with no intervening frames.
- Update the client/server to a matching protocol version that both support chunked responses.
- Catch RpcError and resynchronize: reset/reconnect the RPC stream, since decoder state (_pending) must be discarded.
- Check for concurrent writers on the transport — serialize sends with a lock.
Example fix
# before: interleaving a status event mid-transfer
send({"type": "event", ...}) # interrupts pending chunks
# after: buffer events until the chunk sequence completes
send_all_chunks_first(chunk_id, chunks)
send({"type": "event", ...}) Defensive patterns
Strategy: try-catch
Validate before calling
# Validate frames before feeding the decoder: once a rpc_chunk sequence starts,
# no other frame type may be sent until all `count` chunks arrive.
def validate_chunk_stream(frames):
pending = False
for f in frames:
if pending and not (isinstance(f, dict) and f.get("type") == "rpc_chunk"):
raise ValueError("non-chunk frame inside a chunked RPC sequence")
pending = isinstance(f, dict) and f.get("type") == "rpc_chunk" Type guard
def is_rpc_chunk(value: object) -> bool:
return isinstance(value, dict) and value.get("type") == "rpc_chunk" Try / catch
decoder = _RpcFrameDecoder()
try:
frame = decoder.push(raw_value)
except RpcError as e:
if 'chunk sequence was interrupted' in str(e):
decoder = _RpcFrameDecoder() # reset decoder state, then reconnect/resync
raise ConnectionError('RPC chunked response corrupted; stream resynchronized') from e
raise Prevention
- Emit all chunks of one chunkId back-to-back; never interleave events or other RPC frames.
- Keep client and server protocol versions in sync regarding chunked responses.
- Serialize transport writes (lock) so concurrent sends cannot splice a chunk stream.
- Guard large RPC payloads (>256KB trigger chunking) against mid-stream sender failures and reconnect cleanly.
When it happens
Trigger: A server streaming a chunked RPC response sends a regular frame (event, result, error) between chunks; the chunked message is truncated mid-stream and another message follows; a malformed client injects frames into the stream; multiple writers share the transport without chunk-aware serialization.
Common situations: Custom/older RPC peers that don't implement chunked framing; proxies or loggers rewriting the frame stream; a >256KB RPC payload (forcing chunking) combined with concurrent events on the same connection.
Related errors
- Replacement text is not valid UTF-8: {err}
- invalid glob `{pattern}`: {error}
- Received text_delta for non-text content
- Received text_end for non-text content
- Received thinking_delta for non-thinking content
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/cb9b3f4778b52b50.
Report an issue: GitHub.