can1357/oh-my-pi · error · RpcError

RPC chunk sequence must start at index 0

Error message

RPC chunk sequence must start at index 0

What it means

The client received the first chunk of a new sequence (no pending reassembly in progress), but its index is not 0. Chunk sequences must begin at index 0 so the reassembler can validate ordering and know the stream is complete. A mid-sequence chunk arriving without its head indicates frames were lost, dropped, or the pending state was reset between them.

Source

Thrown at python/omp-rpc/src/omp_rpc/client.py:188

            or index >= count
            or byte_length < _MAX_RPC_FRAME_BYTES
            or byte_length > _MAX_RPC_REASSEMBLED_BYTES
            or not isinstance(data, str)
            or not data
        ):
            raise RpcError("Invalid RPC chunk metadata")
        try:
            chunk = base64.b64decode(data, validate=True)
        except (binascii.Error, ValueError) as exc:
            raise RpcError("Invalid RPC chunk data") from exc
        if base64.b64encode(chunk).decode("ascii") != data:
            raise RpcError("Invalid RPC chunk data")
        if len(chunk) > _RPC_CHUNK_PAYLOAD_BYTES:
            raise RpcError("RPC chunk payload exceeds the transport limit")

        if self._pending is None:
            if index != 0:
                raise RpcError("RPC chunk sequence must start at index 0")
            self._pending = _PendingRpcChunks(chunk_id, count, byte_length)
        pending = self._pending
        if (
            pending.chunk_id != chunk_id
            or pending.count != count
            or pending.byte_length != byte_length
            or pending.next_index != index
        ):
            raise RpcError("RPC chunk sequence mismatch")
        pending.chunks.append(chunk)
        pending.received_bytes += len(chunk)
        pending.next_index += 1
        if pending.received_bytes > pending.byte_length:
            raise RpcError("RPC chunk sequence exceeds its declared length")
        if pending.next_index < pending.count:
            return None
        if pending.received_bytes != pending.byte_length:
            raise RpcError("RPC chunk sequence length mismatch")

View on GitHub (pinned to 9690622007)

Solutions

  1. Make the sender send chunks 0..count-1 atomically with no filtering in between; retransmit the whole sequence on error.
  2. After any RpcError during reassembly, discard ALL remaining chunks of that sequence (match chunkId) instead of continuing to push them.
  3. Verify no middleware/queue drops the first frame of a burst.
  4. Check that a client restart/reconnect resyncs with the sender so sequences restart cleanly.

Example fix

// before
try:
    for frame in frames:
        client.push(frame)  # keeps pushing remaining chunks after an error
except RpcError:
    pass

// after
for frame in frames:
    try:
        client.push(frame)
    except RpcError:
        current_chunk_id = frame.get("chunkId") if isinstance(frame, dict) else None
        frames = [f for f in frames if not (isinstance(f, dict) and f.get("chunkId") == current_chunk_id)]
        # drop rest of sequence, request resend
Defensive patterns

Strategy: try-catch

Validate before calling

def safe_send_sequence(chunks: list[dict]) -> bool:
    if not chunks or chunks[0].get("index") != 0:
        return False
    return True

Type guard

def is_sequence_start(frame: dict) -> bool:
    return isinstance(frame, dict) and frame.get("type") == "rpc_chunk" and frame.get("index") == 0

Try / catch

try:
    client.push(frame)
except RpcError as exc:
    if str(exc) == "RPC chunk sequence must start at index 0":
        logger.error("orphaned chunk (index=%s) with no pending sequence; dropping", frame.get("index"))
        abort_sequence(frame.get("chunkId"))  # drop remaining chunks, request full resend
    else:
        raise

Prevention

When it happens

Trigger: push() of an rpc_chunk with index > 0 while client._pending is None — e.g. the tail chunks of a sequence arrive after an earlier RpcError discarded the pending state, or the first chunk(s) were never delivered.

Common situations: An earlier chunk in the sequence failed validation (raising RpcError and aborting reassembly), leaving orphaned later chunks; frames filtered by a transport/queue; sender restart changed chunkId mid-sequence; a consumer mixing chunks from different sequences after an error.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f8a8fda672f5329b. Report an issue: GitHub.