can1357/oh-my-pi · error · RpcError

RPC chunk sequence exceeds its declared length

Error message

RPC chunk sequence exceeds its declared length

What it means

After appending a valid, in-order chunk, the accumulated decoded bytes exceed the byteLength declared by the first chunk of the sequence. The sender's declared total does not bound the actual payload, so the reassembled frame can never be trusted. The library fails fast instead of silently truncating or accepting a mismatched payload.

Source

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

            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")

        self._pending = None
        try:
            decoded = b"".join(pending.chunks).decode("utf-8")
            frame = json.loads(decoded)
        except (UnicodeDecodeError, json.JSONDecodeError) as exc:
            raise RpcError("Failed to decode reassembled RPC frame") from exc
        if not isinstance(frame, dict):
            raise RpcError("RPC frame must be a JSON object")
        return cast(JsonObject, frame)


def _process_group_id(process: subprocess.Popen[Any]) -> int | None:
    """Process-group id of `process`, or `None` when groups are unavailable.

View on GitHub (pinned to 9690622007)

Solutions

  1. Compute byteLength as len(payload.encode('utf-8')) — the exact decoded byte count — before chunking.
  2. Chunk on encoded bytes, not str characters: split payload.encode('utf-8') into _RPC_CHUNK_PAYLOAD_BYTES slices.
  3. Verify sum(len(chunk) for chunk in chunks) == byteLength on the sender before transmitting.
  4. If the payload can change, recompute chunks and byteLength together atomically.

Example fix

// before
payload = "héllo wörld"
declared = len(payload)  # char count, not bytes
send_chunks(payload, byteLength=declared)

// after
payload_bytes = payload.encode("utf-8")
send_chunks(payload_bytes, byteLength=len(payload_bytes))
Defensive patterns

Strategy: validation

Validate before calling

def prepare_sequence(payload: bytes, chunk_size: int) -> tuple[list[bytes], int]:
    chunks = [payload[i:i + chunk_size] for i in range(0, len(payload), chunk_size)]
    byte_length = len(payload)
    assert sum(len(c) for c in chunks) == byte_length
    return chunks, byte_length

Type guard

def declared_size_matches(chunks: list[bytes], byte_length: int) -> bool:
    return sum(len(c) for c in chunks) == byte_length

Try / catch

try:
    client.push(frame)
except RpcError as exc:
    if str(exc) == "RPC chunk sequence exceeds its declared length":
        logger.error("sender byteLength=%s too small; aborting sequence", pending_declared)
        abort_and_request_resend()
    else:
        raise

Prevention

When it happens

Trigger: push() of a chunk that pushes pending.received_bytes past pending.byte_length — typically a sender that miscounted the payload size (e.g. chunked by characters of a str instead of UTF-8 bytes) or appended extra chunks.

Common situations: Sender computed byteLength with len(string) but payloads contain multi-byte UTF-8 characters; sender added a terminating extra chunk; chunk boundaries computed on the base64 string rather than decoded bytes; payload mutated between the byteLength computation and chunking.

Related errors


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