{"record":{"id":"2cb91a86aca05165","repo":"FoundationAgents/OpenManus","slug":"failed-to-get-socket-connection","errorCode":null,"errorMessage":"Failed to get socket connection","messagePattern":"Failed to get socket connection","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/sandbox/core/terminal.py","lineNumber":71,"sourceCode":"            stdin=True,\n            tty=True,\n            stdout=True,\n            stderr=True,\n            privileged=True,\n            user=\"root\",\n            environment={**env_vars, \"TERM\": \"dumb\", \"PS1\": \"$ \", \"PROMPT_COMMAND\": \"\"},\n        )\n        self.exec_id = exec_data[\"Id\"]\n\n        socket_data = self.api.exec_start(\n            self.exec_id, socket=True, tty=True, stream=True, demux=True\n        )\n\n        if hasattr(socket_data, \"_sock\"):\n            self.socket = socket_data._sock\n            self.socket.setblocking(False)\n        else:\n            raise RuntimeError(\"Failed to get socket connection\")\n\n        await self._read_until_prompt()\n\n    async def close(self) -> None:\n        \"\"\"Cleans up session resources.\n\n        1. Sends exit command\n        2. Closes socket connection\n        3. Checks and cleans up exec instance\n        \"\"\"\n        try:\n            if self.socket:\n                # Send exit command to close bash session\n                try:\n                    self.socket.sendall(b\"exit\\n\")\n                    # Allow time for command execution\n                    await asyncio.sleep(0.1)\n                except:","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/FoundationAgents/OpenManus/blob/52a13f2a57d8c7f6737eefb02ccf569594d44273/app/sandbox/core/terminal.py#L53-L89","documentation":"After docker-py's exec_start(socket=True, tty=True, stream=True, demux=True), the code reaches into the private attribute socket_data._sock to grab the raw socket. If the returned object does not expose _sock (its shape differs across docker SDK versions and tty/demux combinations), terminal initialization fails with this RuntimeError. It is an implementation-detail dependency: docker-py does not guarantee _sock on every return type.","triggerScenarios":"Calling DockerSession.__init__/create with a docker SDK version where exec_start returns a SocketIORunner, a wrapped socket, or a tuple (because demux=True changes the return shape) that lacks the _sock attribute. Mixing demux=True with tty=True is a known combination that changes the object shape.","commonSituations":"Upgrading or downgrading the 'docker' package in the environment; using a docker-py fork (docker-pydx) with a different socket plumbing layer; running against a docker daemon version whose API version renegotiation changes the returned object.","solutions":["Pin the docker SDK version this code was developed against (check requirements/lockfile) — _sock access is version-sensitive.","Drop demux=True when tty=True is used; the demux flag alters the returned structure and is redundant with a TTY (stdout/stderr are merged on a tty anyway).","Handle more return shapes: check for _sock, then .sock, then treat the object itself as a socket (hasattr sendall/setblocking).","Print type(socket_data) in a debug run to see exactly what your docker version returns before patching."],"exampleFix":"# before\nsocket_data = self.api.exec_start(self.exec_id, socket=True, tty=True, stream=True, demux=True)\nif hasattr(socket_data, \"_sock\"):\n    self.socket = socket_data._sock\nelse:\n    raise RuntimeError(\"Failed to get socket connection\")\n\n# after\nsocket_data = self.api.exec_start(self.exec_id, socket=True, tty=True, stream=True)\nif hasattr(socket_data, \"_sock\"):\n    self.socket = socket_data._sock\nelif hasattr(socket_data, \"sendall\"):\n    self.socket = socket_data\nelse:\n    raise RuntimeError(f\"Unexpected exec_start return type: {type(socket_data)!r}\")\nself.socket.setblocking(False)","handlingStrategy":"type-guard","validationCode":"import docker, pkg_resources\nmajor_minor = tuple(int(x) for x in docker.__version__.split('.')[:2])\nassert major_minor == (7, 1), f'untested docker SDK {docker.__version__} for raw socket access'","typeGuard":"def as_raw_socket(obj):\n    \"\"\"Extract a socket-like object from docker exec_start output.\"\"\"\n    for attr in ('_sock', 'sock', '_sock_obj'):\n        s = getattr(obj, attr, None)\n        if s is not None and hasattr(s, 'sendall') and hasattr(s, 'setblocking'):\n            return s\n    if hasattr(obj, 'sendall'):\n        return obj\n    return None","tryCatchPattern":"try:\n    await session.create(workdir, env)\nexcept RuntimeError as e:\n    if 'Failed to get socket connection' in str(e):\n        raise RuntimeError(\n            'docker SDK returned an unexpected exec_start shape; pin docker==7.1.0 '\n            'or drop demux=True'\n        ) from e\n    raise","preventionTips":["Pin the docker package version in requirements/lockfile.","Avoid combining demux=True with tty=True.","Never rely on private attributes (_sock) without a fallback path."],"tags":["docker","socket","version-compat","terminal"],"backgroundTag":null,"analyzedSha":"52a13f2a57d8c7f6737eefb02ccf569594d44273","analyzedAt":"2026-08-15T02:33:49.993Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}