CoplayDev/unity-mcp · error · ValueError

Invalid framed length

Error message

Invalid framed length: {payload_len}

What it means

Raised in the framed receive loop (unity_connection.py:198) when the 8-byte big-endian length prefix decodes to a value greater than FRAMED_MAX (64 MiB). This is a defensive guard against a corrupted or misaligned stream that would otherwise trigger a huge allocation.

Solutions

  1. Verify the Python server and MCPForUnity Unity package are on compatible versions (both must agree on framing).
  2. Ensure only one client owns the stdio port — new stdio connections stomp old ones.
  3. Drop the socket and reconnect to re-synchronize the stream (send_command does this on retry).

Example fix

// before — shared port, mixed traffic corrupts the framed stream

// after — one owner per port; reconnect to resync
conn.disconnect()
conn.connect()
Defensive patterns

Strategy: try-catch

Validate before calling

FRAMED_MAX = 64 * 1024 * 1024

def framed_length_plausible(length: int) -> bool:
    return 0 <= length <= FRAMED_MAX

Type guard

def is_invalid_framed_length(e: BaseException) -> bool:
    return isinstance(e, ValueError) and 'Invalid framed length' in str(e)

Try / catch

try:
    data = conn.receive_full_response(conn.sock)
except ValueError as e:
    if 'Invalid framed length' in str(e):
        # stream desync — drop socket, reconnect to resync
        conn.disconnect()
        conn.connect()
        data = conn.receive_full_response(conn.sock)
    else:
        raise

Prevention

When it happens

Trigger: receive_full_response reads a length prefix that is garbage — protocol desync, a peer writing raw plaintext onto a connection that negotiated framing, or memory/stream corruption producing an absurd length.

Common situations: Version/transport mismatch where one side frames and the other sends legacy plaintext, a partial read making the 8 header bytes line up wrong, or two clients stomping the same stdio port.

Related errors


AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13). Data as JSON: /api/errors/cda99d517a337be8. Report an issue: GitHub.

Appendix: source

Thrown at Server/src/transport/legacy/unity_connection.py:198

            heartbeat_limit = getattr(config, 'max_heartbeat_frames', 16)
            heartbeat_window = getattr(config, 'heartbeat_timeout', 2.0)
            heartbeat_started = time.monotonic()
            heartbeat_count = 0
            try:
                while True:
                    header = self._read_exact(sock, 8)
                    payload_len = struct.unpack('>Q', header)[0]
                    if payload_len == 0:
                        heartbeat_count += 1
                        logger.debug(
                            f"Received heartbeat frame #{heartbeat_count}")
                        if heartbeat_count >= heartbeat_limit or (time.monotonic() - heartbeat_started) > heartbeat_window:
                            raise TimeoutError(
                                "Unity sent heartbeat frames without payload within configured threshold"
                            )
                        continue
                    if payload_len > FRAMED_MAX:
                        raise ValueError(
                            f"Invalid framed length: {payload_len}")
                    payload = self._read_exact(sock, payload_len)
                    logger.debug(
                        f"Received framed response ({len(payload)} bytes)")
                    return payload
            except socket.timeout as exc:
                logger.warning("Socket timeout during framed receive")
                raise TimeoutError("Timeout receiving Unity response") from exc
            except TimeoutError:
                raise
            except Exception as exc:
                logger.error(f"Error during framed receive: {exc}")
                raise

        chunks = []
        # Respect the socket's currently configured timeout
        try:
            while True:

View on GitHub (pinned to c21bf496bc)