{"record":{"id":"53755d42b2541ec1","repo":"CoplayDev/unity-mcp","slug":"invalid-frame-length-length","errorCode":null,"errorMessage":"Invalid frame length: {length}","messagePattern":"Invalid frame length: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/stress_editor_state.py","lineNumber":66,"sourceCode":"            pass\n    return default_port\n\n\nasync def read_exact(reader: asyncio.StreamReader, n: int) -> bytes:\n    buf = b\"\"\n    while len(buf) < n:\n        chunk = await reader.read(n - len(buf))\n        if not chunk:\n            raise ConnectionError(\"Connection closed while reading\")\n        buf += chunk\n    return buf\n\n\nasync def read_frame(reader: asyncio.StreamReader) -> bytes:\n    header = await read_exact(reader, 8)\n    (length,) = struct.unpack(\">Q\", header)\n    if length <= 0 or length > (64 * 1024 * 1024):\n        raise ValueError(f\"Invalid frame length: {length}\")\n    return await read_exact(reader, length)\n\n\nasync def write_frame(writer: asyncio.StreamWriter, payload: bytes) -> None:\n    header = struct.pack(\">Q\", len(payload))\n    writer.write(header)\n    writer.write(payload)\n    await asyncio.wait_for(writer.drain(), timeout=TIMEOUT)\n\n\nasync def do_handshake(reader: asyncio.StreamReader) -> None:\n    line = await reader.readline()\n    if not line or b\"WELCOME UNITY-MCP\" not in line:\n        raise ConnectionError(f\"Unexpected handshake from server: {line!r}\")\n\n\ndef make_get_editor_state_frame() -> bytes:\n    payload = {\"type\": \"get_editor_state\", \"params\": {}}","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/CoplayDev/unity-mcp/blob/c21bf496bca87d54e75bad048563c3adb1782081/tools/stress_editor_state.py#L48-L84","documentation":"Raised by read_frame() in stress_editor_state.py after unpacking the 8-byte big-endian frame header. The decoded length must be in (0, 64MB]; values outside that range indicate the byte stream is desynchronized — the 8 bytes read as a header are actually payload or garbage, not a valid length prefix. A length of 0 or a value >64MiB means framing alignment is broken.","triggerScenarios":"Stream desynchronization: the reader consumed the wrong number of bytes on a prior frame (e.g. a handshake line was partially consumed before framing began), the server sent an unsolicited message that shifted alignment, or the client connected to a service that does not use the '>Q' length-prefixed framing protocol.","commonSituations":"Connecting to the wrong port (e.g. the HTTP MCP endpoint instead of the raw TCP bridge); the bridge sent extra bytes during/after the handshake line that the reader didn't drain; a prior read_frame call returned early due to a timeout leaving partial bytes in the buffer.","solutions":["Verify you are connecting to the TCP bridge port (from unity-mcp-status-*.json unity_port), not the HTTP server port.","Ensure the handshake line (WELCOME UNITY-MCP...) is fully consumed by readline() before the first read_frame call.","If framing is persistently broken, the protocol version may differ — check the bridge's framing negotiation."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    response = await asyncio.wait_for(read_frame(reader), timeout=TIMEOUT)\nexcept (ValueError, ConnectionError, asyncio.TimeoutError) as e:\n    # Framing is desynchronized — close and reconnect with a fresh reader.\n    writer.close()\n    await writer.wait_closed()\n    reader, writer = await asyncio.open_connection(host, port)\n    await do_handshake(reader)","preventionTips":["Always reconnect after a framing error — do not reuse the desynchronized StreamReader.","Confirm you are connecting to the TCP bridge port, not the HTTP MCP port.","Ensure the handshake line is fully consumed before the first framed read."],"tags":["stress-test","network","tcp","protocol","framing","unity-bridge"],"backgroundTag":null,"analyzedSha":"c21bf496bca87d54e75bad048563c3adb1782081","analyzedAt":"2026-08-13T17:36:56.095Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}