{"record":{"id":"7f479f2f1d410cc1","repo":"can1357/oh-my-pi","slug":"rpc-chunk-payload-exceeds-the-transport-limit-7f479f","errorCode":null,"errorMessage":"RPC chunk payload exceeds the transport limit","messagePattern":"RPC chunk payload exceeds the transport limit","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":184,"sourceCode":"            or isinstance(byte_length, bool)\n            or index < 0\n            or count < 2\n            or count > max_chunk_count\n            or index >= count\n            or byte_length < _MAX_RPC_FRAME_BYTES\n            or byte_length > _MAX_RPC_REASSEMBLED_BYTES\n            or not isinstance(data, str)\n            or not data\n        ):\n            raise RpcError(\"Invalid RPC chunk metadata\")\n        try:\n            chunk = base64.b64decode(data, validate=True)\n        except (binascii.Error, ValueError) as exc:\n            raise RpcError(\"Invalid RPC chunk data\") from exc\n        if base64.b64encode(chunk).decode(\"ascii\") != data:\n            raise RpcError(\"Invalid RPC chunk data\")\n        if len(chunk) > _RPC_CHUNK_PAYLOAD_BYTES:\n            raise RpcError(\"RPC chunk payload exceeds the transport limit\")\n\n        if self._pending is None:\n            if index != 0:\n                raise RpcError(\"RPC chunk sequence must start at index 0\")\n            self._pending = _PendingRpcChunks(chunk_id, count, byte_length)\n        pending = self._pending\n        if (\n            pending.chunk_id != chunk_id\n            or pending.count != count\n            or pending.byte_length != byte_length\n            or pending.next_index != index\n        ):\n            raise RpcError(\"RPC chunk sequence mismatch\")\n        pending.chunks.append(chunk)\n        pending.received_bytes += len(chunk)\n        pending.next_index += 1\n        if pending.received_bytes > pending.byte_length:\n            raise RpcError(\"RPC chunk sequence exceeds its declared length\")","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L166-L202","documentation":"The individual chunk's decoded payload is larger than _RPC_CHUNK_PAYLOAD_BYTES, the maximum bytes a single chunk may carry. Even though the base64 string was valid, the sender packed more payload per chunk than the transport allows. The limit exists so no single frame exceeds transport frame-size constraints after base64 encoding.","triggerScenarios":"push() of an rpc_chunk whose data decodes to more than _RPC_CHUNK_PAYLOAD_BYTES bytes — e.g. the sender used a larger chunk size than the client's compile-time transport limit.","commonSituations":"Sender and receiver configured with different max-frame sizes (sender raised its chunk size, client didn't); a sender that chunks by character count of the base64 string instead of decoded byte count; protocol version mismatch where limits changed between releases.","solutions":["Re-chunk on the sender using the same limit the client enforces (_RPC_CHUNK_PAYLOAD_BYTES decoded bytes per chunk).","Align both endpoints to the same omp-rpc version so chunk-size limits match.","If you control chunking, size chunks conservatively (e.g. under the limit by a margin) and split by decoded byte length, not base64 string length.","Catch RpcError, log len(data)//4*3 as an estimate of payload size, and adjust the sender's chunk size accordingly."],"exampleFix":"// before\nCHUNK = 1_000_000  # too big for client transport\nfor i in range(0, len(payload), CHUNK):\n    send_chunk(payload[i:i+CHUNK])\n\n// after\nCHUNK = _RPC_CHUNK_PAYLOAD_BYTES  # match the client's transport limit\nfor i in range(0, len(payload), CHUNK):\n    send_chunk(payload[i:i+CHUNK])","handlingStrategy":"validation","validationCode":"def chunk_payload(payload: bytes, limit: int) -> list[bytes]:\n    if limit <= 0:\n        raise ValueError(\"limit must be positive\")\n    return [payload[i:i + limit] for i in range(0, len(payload), limit)] or [b\"\"]\n# call with limit equal to the client's _RPC_CHUNK_PAYLOAD_BYTES","typeGuard":"def within_transport_limit(chunk: bytes, limit: int) -> bool:\n    return len(chunk) <= limit","tryCatchPattern":"try:\n    client.push(frame)\nexcept RpcError as exc:\n    if \"transport limit\" in str(exc):\n        logger.error(\"chunk too large (%d bytes); re-chunk smaller\", len(frame.get(\"data\", \"\")) * 3 // 4)\n        rechunk_and_resend(smaller_limit)\n    else:\n        raise","preventionTips":["Share a single constant for max chunk size between sender and receiver code.","Chunk by decoded byte length, never by base64 string length.","Add an integration test sending a payload just above and just below the limit."],"tags":["rpc","chunking","limits","protocol"],"backgroundTag":"rpc-chunk-size-exceeded","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}