can1357/oh-my-pi · error · RpcError

RPC chunk sequence length mismatch

Error message

RPC chunk sequence length mismatch

What it means

All chunks of the sequence arrived (next_index reached count) but the accumulated byte total does not equal the declared byteLength — the sequence is short (received < declared). Chunk counts matched yet bytes don't, meaning chunks were consistent in metadata but the sender's declared size or last-chunk content was wrong. The reassembler requires an exact byte match before decoding the frame.

Source

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

                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.

    Captured right after spawn so teardown can signal the whole group even
    after the leader is reaped — POSIX `os.getpgid` fails on a reaped pid.
    """

View on GitHub (pinned to 9690622007)

Solutions

  1. Assert on the sender: sum(len(c) for c in chunks) == byteLength before sending; fix the computation if not.
  2. Re-read the source payload fully (ensure no truncated file/stream read) and re-chunk.
  3. Derive byteLength from the chunks actually produced, not from a precomputed expected size.
  4. Enable logging of declared vs received byte counts on both ends to pinpoint which side miscounts.

Example fix

// before
byte_length = expected_size          # from metadata, may be stale
chunks = split(payload_bytes)
send(chunks, byte_length)            # short payload -> mismatch

// after
chunks = split(payload_bytes)
byte_length = sum(len(c) for c in chunks)  # derived from actual chunks
assert byte_length == len(payload_bytes)
send(chunks, byte_length)
Defensive patterns

Strategy: validation

Validate before calling

def verify_before_send(chunks: list[bytes], byte_length: int) -> None:
    received = sum(len(c) for c in chunks)
    if received != byte_length:
        raise ValueError(f"declared {byte_length} but chunks total {received}")

Type guard

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

Try / catch

try:
    frame = client.push(frame)
except RpcError as exc:
    if str(exc) == "RPC chunk sequence length mismatch":
        logger.error("sequence complete but bytes=%d != declared=%d", received_bytes, declared_bytes)
        log_debug_counts_and_request_resend()
    else:
        raise

Prevention

When it happens

Trigger: push() of the final chunk of a sequence where pending.received_bytes != pending.byte_length — the sender declared a larger byteLength than the actual payload it chunked (short read, truncated payload, inflated declared size).

Common situations: Sender read the payload from a file/stream and hit EOF early while declaring the expected size; sender padded byteLength to a boundary; byteLength computed from a different (newer/older) version of the payload than the one chunked; empty-chunk edge cases.

Related errors


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