FoundationAgents/OpenManus · error · RuntimeError

Failed to get socket connection

Error message

Failed to get socket connection

What it means

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.

Source

Thrown at app/sandbox/core/terminal.py:71

            stdin=True,
            tty=True,
            stdout=True,
            stderr=True,
            privileged=True,
            user="root",
            environment={**env_vars, "TERM": "dumb", "PS1": "$ ", "PROMPT_COMMAND": ""},
        )
        self.exec_id = exec_data["Id"]

        socket_data = self.api.exec_start(
            self.exec_id, socket=True, tty=True, stream=True, demux=True
        )

        if hasattr(socket_data, "_sock"):
            self.socket = socket_data._sock
            self.socket.setblocking(False)
        else:
            raise RuntimeError("Failed to get socket connection")

        await self._read_until_prompt()

    async def close(self) -> None:
        """Cleans up session resources.

        1. Sends exit command
        2. Closes socket connection
        3. Checks and cleans up exec instance
        """
        try:
            if self.socket:
                # Send exit command to close bash session
                try:
                    self.socket.sendall(b"exit\n")
                    # Allow time for command execution
                    await asyncio.sleep(0.1)
                except:

View on GitHub (pinned to 52a13f2a57)

Solutions

  1. Pin the docker SDK version this code was developed against (check requirements/lockfile) — _sock access is version-sensitive.
  2. 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).
  3. Handle more return shapes: check for _sock, then .sock, then treat the object itself as a socket (hasattr sendall/setblocking).
  4. Print type(socket_data) in a debug run to see exactly what your docker version returns before patching.

Example fix

# before
socket_data = self.api.exec_start(self.exec_id, socket=True, tty=True, stream=True, demux=True)
if hasattr(socket_data, "_sock"):
    self.socket = socket_data._sock
else:
    raise RuntimeError("Failed to get socket connection")

# after
socket_data = self.api.exec_start(self.exec_id, socket=True, tty=True, stream=True)
if hasattr(socket_data, "_sock"):
    self.socket = socket_data._sock
elif hasattr(socket_data, "sendall"):
    self.socket = socket_data
else:
    raise RuntimeError(f"Unexpected exec_start return type: {type(socket_data)!r}")
self.socket.setblocking(False)
Defensive patterns

Strategy: type-guard

Validate before calling

import docker, pkg_resources
major_minor = tuple(int(x) for x in docker.__version__.split('.')[:2])
assert major_minor == (7, 1), f'untested docker SDK {docker.__version__} for raw socket access'

Type guard

def as_raw_socket(obj):
    """Extract a socket-like object from docker exec_start output."""
    for attr in ('_sock', 'sock', '_sock_obj'):
        s = getattr(obj, attr, None)
        if s is not None and hasattr(s, 'sendall') and hasattr(s, 'setblocking'):
            return s
    if hasattr(obj, 'sendall'):
        return obj
    return None

Try / catch

try:
    await session.create(workdir, env)
except RuntimeError as e:
    if 'Failed to get socket connection' in str(e):
        raise RuntimeError(
            'docker SDK returned an unexpected exec_start shape; pin docker==7.1.0 '
            'or drop demux=True'
        ) from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15). Data as JSON: /api/errors/2cb91a86aca05165. Report an issue: GitHub.