# Buggy code
def exec_start(self, exec_id, detach=False, tty=False, stream=False, socket=False):
    """
    Start a previously set up exec instance.

    Args:
        exec_id (str): ID of the exec instance
        detach (bool): If true, detach from the exec command.
            Default: False
        tty (bool): Allocate a pseudo-TTY. Default: False
        stream (bool): Stream response data. Default: False

    Returns:
        (generator or str): If ``stream=True``, a generator yielding
        response chunks. A string containing response data otherwise.

    Raises:
        :py:class:`docker.errors.APIError`
            If the server returns an error.
    """
    # we want opened socket if socket == True
    if isinstance(exec_id, dict):
        exec_id = exec_id.get("Id")

    data = {"Tty": tty, "Detach": detach}

    headers = {} if detach else {"Connection": "Upgrade", "Upgrade": "tcp"}

    res = self._post_json(
        self._url("/exec/{0}/start", exec_id), headers=headers, data=data, stream=True
    )

    if socket:
        return self._get_raw_response_socket(res)
    return self._read_from_socket(res, stream)


# Traceback (SocketError)
In [9]: import docker

In [10]: docker.version
Out[10]: '1.10.4'

In [11]: cli = docker.Client()

In [12]: container = cli.create_container('python:2.7.11', command='sleep 1h')

In [13]: cli.start(container['Id'])

In [14]: e = cli.exec_create(container['Id'], 'echo "123"')

In [15]: cli.exec_start(e['Id'], detach=True)
^C---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-15-d3ef5f6326d6> in <module>()
----> 1 cli.exec_start(e['Id'], detach=True)

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/utils/decorators.pyc in wrapper(self, *args, **kwargs)
33                     )
34                 )
---> 35             return f(self, *args, **kwargs)
36         return wrapper
37     return decorator

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/api/exec_api.pyc in exec_start(self, exec_id, detach, tty, stream, socket)
79         if socket:
80             return self._get_raw_response_socket(res)
---> 81         return self._read_from_socket(res, stream)

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/client.pyc in _read_from_socket(self, response, stream)
324             return frames_iter(socket)
325         else:
--> 326             return six.binary_type().join(frames_iter(socket))
327
328     def _disable_socket_timeout(self, socket):

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/utils/socket.pyc in frames_iter(socket)
70     Returns a generator of frames read from socket
71     """
---> 72     n = next_frame_size(socket)
73     while n > 0:
74         yield read(socket, n)

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/utils/socket.pyc in next_frame_size(socket)
58     """
59     try:
---> 60         data = read_exactly(socket, 8)
61     except SocketError:
62         return 0

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/utils/socket.pyc in read_exactly(socket, n)
43     data = six.binary_type()
44     while len(data) < n:
---> 45         next_data = read(socket, n - len(data))
46         if not next_data:
47             raise SocketError("Unexpected EOF")

/usr/local/pyenv/versions/2.7.12/lib/python2.7/site-packages/docker/utils/socket.pyc in read(socket, n)
25     # wait for data to become available
26     if not isinstance(socket, NpipeSocket):
---> 27         select.select([socket], [], [])
28
29     try:

KeyboardInterrupt:

# Fixed code
def exec_start(self, exec_id, detach=False, tty=False, stream=False, socket=False):
    """
    Start a previously set up exec instance.

    Args:
        exec_id (str): ID of the exec instance
        detach (bool): If true, detach from the exec command.
            Default: False
        tty (bool): Allocate a pseudo-TTY. Default: False
        stream (bool): Stream response data. Default: False

    Returns:
        (generator or str): If ``stream=True``, a generator yielding
        response chunks. A string containing response data otherwise.

    Raises:
        :py:class:`docker.errors.APIError`
            If the server returns an error.
    """
    # we want opened socket if socket == True
    if isinstance(exec_id, dict):
        exec_id = exec_id.get("Id")

    data = {"Tty": tty, "Detach": detach}

    headers = {} if detach else {"Connection": "Upgrade", "Upgrade": "tcp"}

    res = self._post_json(
        self._url("/exec/{0}/start", exec_id), headers=headers, data=data, stream=True
    )
    if detach:
        return self._result(res)
    if socket:
        return self._get_raw_response_socket(res)
    return self._read_from_socket(res, stream)