# Buggy code
def join(self, output=None, consume_output=False, timeout=None, encoding="utf-8"):
    """Wait until all remote commands in output have finished.
    Does *not* block other commands from running in parallel.

    :param output: Output of commands to join on
    :type output: `HostOutput` objects
    :param consume_output: Whether or not join should consume output
      buffers. Output buffers will be empty after ``join`` if set
      to ``True``. Must be set to ``True`` to allow host logger to log
      output on call to ``join`` when host logger has been enabled.
    :type consume_output: bool
    :param timeout: Timeout in seconds if **all** remote commands are not
      yet finished.
      This function's timeout is for all commands in total and will therefor
      be affected by pool size and total number of concurrent commands in
      self.pool.
      Since self.timeout is passed onto each individual SSH session it is
      **not** used for any parallel functions like `run_command` or `join`.
    :type timeout: int
    :param encoding: Unused - encoding from each ``HostOutput`` is used instead.
      To be removed in future releases.
    :type encoding: str

    :raises: :py:class:`pssh.exceptions.Timeout` on timeout requested and
      reached with commands still running.

    :rtype: ``None``"""
    if output is None:
        output = self.get_last_output()
    elif not isinstance(output, list):
        raise ValueError("Unexpected output object type")
    cmds = [
        self.pool.spawn(
            self._join,
            host_out,
            timeout=timeout,
            consume_output=consume_output,
            encoding=encoding,
        )
        for host_i, host_out in enumerate(output)
    ]
    # Errors raised by self._join should be propagated.
    finished_cmds = joinall(cmds, raise_error=True, timeout=timeout)
    if timeout is None:
        return
    unfinished_cmds = set.difference(set(cmds), set(finished_cmds))
    if unfinished_cmds:
        finished_output = self.get_last_output(cmds=finished_cmds)
        unfinished_output = list(set.difference(set(output), set(finished_output)))
        raise Timeout(
            "Timeout of %s sec(s) reached with commands still running",
            timeout,
            finished_output,
            unfinished_output,
        )


# Traceback (pssh.exceptions.AuthenticationException)
(coba2) debian@debian-mon:~/coba2$ ssh root@10.90.200.55 -p 3322
Last login: Fri Sep 18 10:23:25 2020 from 10.90.200.57
[root@candibinangun ~]# exit
logout
Connection to 10.90.200.55 closed.

(coba2) debian@debian-mon:~/coba2$ python
Python 3.8.5 (default, Aug 28 2020, 06:44:01)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
from pssh.clients import SSHClient
sshObj=SSHClient('10.90.200.55', user='root', port=3322, num_retries=3, retry_delay=5, timeout=5)
Traceback (most recent call last):
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 93, in _auth_retry
self.auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/native/single.py", line 179, in auth
self._identity_auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 183, in _identity_auth
raise AuthenticationException("No authentication methods succeeded")
pssh.exceptions.AuthenticationException: No authentication methods succeeded

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 93, in _auth_retry
self.auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/native/single.py", line 179, in auth
self._identity_auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 183, in _identity_auth
raise AuthenticationException("No authentication methods succeeded")
pssh.exceptions.AuthenticationException: No authentication methods succeeded

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 93, in _auth_retry
self.auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/native/single.py", line 179, in auth
self._identity_auth()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 183, in _identity_auth
raise AuthenticationException("No authentication methods succeeded")
pssh.exceptions.AuthenticationException: No authentication methods succeeded

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/native/single.py", line 103, in __init__
super(SSHClient, self).__init__(
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 80, in __init__
self._init()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 85, in _init
self._auth_retry()
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 97, in _auth_retry
return self._auth_retry(retries=retries+1)
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 97, in _auth_retry
return self._auth_retry(retries=retries+1)
File "/home/debian/.local/share/virtualenvs/coba2-gQE_YhKQ/lib/python3.8/site-packages/pssh/clients/base/single.py", line 99, in _auth_retry
raise AuthenticationException(msg, self.host, self.port, ex)
pssh.exceptions.AuthenticationException: ('Authentication error while connecting to %s:%s - %s', '10.90.200.55', 3322, AuthenticationException('No authentication methods succeeded'))

# Fixed code
def join(self, output=None, consume_output=False, timeout=None, encoding="utf-8"):
    """Wait until all remote commands in output have finished.
    Does *not* block other commands from running in parallel.

    :param output: Output of commands to join on
    :type output: `HostOutput` objects
    :param consume_output: Whether or not join should consume output
      buffers. Output buffers will be empty after ``join`` if set
      to ``True``. Must be set to ``True`` to allow host logger to log
      output on call to ``join`` when host logger has been enabled.
    :type consume_output: bool
    :param timeout: Timeout in seconds if **all** remote commands are not
      yet finished.
      This function's timeout is for all commands in total and will therefor
      be affected by pool size and total number of concurrent commands in
      self.pool.
      Since self.timeout is passed onto each individual SSH session it is
      **not** used for any parallel functions like `run_command` or `join`.
    :type timeout: int
    :param encoding: Unused - encoding from each ``HostOutput`` is used instead.
      To be removed in future releases.
    :type encoding: str

    :raises: :py:class:`pssh.exceptions.Timeout` on timeout requested and
      reached with commands still running.

    :rtype: ``None``"""
    if output is None:
        output = self.get_last_output()
    elif not isinstance(output, list):
        raise ValueError("Unexpected output object type")
    cmds = [
        self.pool.spawn(
            self._join,
            host_out,
            timeout=timeout,
            consume_output=consume_output,
            encoding=encoding,
        )
        for host_i, host_out in enumerate(output)
    ]
    # Errors raised by self._join should be propagated.
    finished_cmds = joinall(cmds, raise_error=True, timeout=timeout)
    if timeout is None:
        return
    unfinished_cmds = set.difference(set(cmds), set(finished_cmds))
    if unfinished_cmds:
        finished_output = self.get_last_output(cmds=finished_cmds)
        unfinished_output = list(set.difference(set(output), set(finished_output)))
        raise Timeout(
            "Timeout of %s sec(s) reached with commands still running",
            timeout,
            finished_output,
            unfinished_output,
        )