{"record":{"id":"36455c9335d979fb","repo":"CoplayDev/unity-mcp","slug":"connection-closed-while-reading-36455c","errorCode":null,"errorMessage":"Connection closed while reading","messagePattern":"Connection closed while reading","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"warning","filePath":"tools/stress_mcp.py","lineNumber":58,"sourceCode":"            if project_path:\n                # Match status for the given project if possible\n                if proj and project_path in proj:\n                    if 0 < port < 65536:\n                        return port\n            else:\n                if 0 < port < 65536:\n                    return port\n        except Exception:\n            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","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/CoplayDev/unity-mcp/blob/c21bf496bca87d54e75bad048563c3adb1782081/tools/stress_mcp.py#L40-L76","documentation":"Raised by read_exact() in stress_mcp.py when asyncio.StreamReader.read() returns empty bytes before the full requested length is received, indicating the Unity MCP bridge closed the TCP connection. Under the multi-client stress test this is a routine event — connections are churned, the bridge restarts on domain reload, and the client_loop catches this and reconnects with backoff.","triggerScenarios":"The bridge dropped the connection during a ping/read cycle: editor recompilation triggered a domain reload (bridge restart), the number of concurrent clients exceeded the bridge's connection cap, or the editor was closed/crashed. Also fires when connecting to a port where nothing is listening and the OS resets immediately.","commonSituations":"Running stress_mcp.py with high --clients during Unity recompilation; the bridge's max-connection limit is lower than the client count; editor closed mid-run; loopback socket reset by the OS.","solutions":["Expected under stress — client_loop catches ConnectionError/OSError and reconnects with exponential backoff. Monitor 'disconnects' in the stats output.","Reduce --clients if disconnects dominate successful pings, indicating the bridge's connection ceiling is the bottleneck.","Ensure Unity is open and the bridge is active before launching; check unity_port in the status JSON.","Pause the reload_churn_task or reduce storm-count if domain reloads are tearing down the bridge too frequently."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import socket\n\ndef bridge_listening(host: str, port: int) -> bool:\n    try:\n        with socket.create_connection((host, port), timeout=2.0):\n            return True\n    except OSError:\n        return False","typeGuard":null,"tryCatchPattern":"# client_loop already handles this:\nexcept (ConnectionError, OSError, asyncio.IncompleteReadError, asyncio.TimeoutError):\n    stats[\"disconnects\"] += 1\n    await asyncio.sleep(reconnect_delay)\n    reconnect_delay = min(reconnect_delay * 1.5, 2.0)\n    continue","preventionTips":["Connection drops are expected during stress — rely on the built-in reconnect-with-backoff.","Tune --clients to stay under the bridge's connection ceiling.","Avoid running during heavy recompilation unless testing reconnect behavior specifically."],"tags":["stress-test","network","tcp","unity-bridge","connection"],"backgroundTag":null,"analyzedSha":"c21bf496bca87d54e75bad048563c3adb1782081","analyzedAt":"2026-08-13T17:36:56.095Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}