# Buggy code
def destroy(self):
    if hasattr(self, "stream"):
        # TODO: Optionally call stream.close() on newer pyzmq? It is broken on some.
        self.stream.io_loop.remove_handler(self.stream.socket)
        self.stream.socket.close()
        self.socket.close()
    self.context.term()


# Traceback (KeyError)
[boucha@elsapo ~]$ sudo salt-call cp.push ~/davescripts/empty.txt -l debug
[DEBUG   ] Reading configuration from /etc/salt/minion
[DEBUG   ] Including configuration from '/etc/salt/minion.d/_schedule.conf'
[DEBUG   ] Reading configuration from /etc/salt/minion.d/_schedule.conf
[DEBUG   ] Using cached minion ID from /etc/salt/minion_id: dasalt
[DEBUG   ] Configuration file path: /etc/salt/minion
[DEBUG   ] Reading configuration from /etc/salt/minion
[DEBUG   ] Including configuration from '/etc/salt/minion.d/_schedule.conf'
[DEBUG   ] Reading configuration from /etc/salt/minion.d/_schedule.conf
[DEBUG   ] Please install 'virt-what' to improve results of the 'virtual' grain.
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506', 'aes')
[DEBUG   ] Initializing new SAuth for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506')
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506', 'clear')
[DEBUG   ] Decrypting the current master AES key
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] LazyLoaded jinja.render
[DEBUG   ] LazyLoaded yaml.render
[DEBUG   ] LazyLoaded cp.push
[DEBUG   ] Trying to copy '/home/boucha/davescripts/empty.txt' to master
[DEBUG   ] Initializing new SAuth for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506')
[DEBUG   ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506', 'aes')
[DEBUG   ] Initializing new SAuth for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506')
[DEBUG   ] Error deleting fd from IOLoop
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/tornado/ioloop.py", line 691, in remove_handler
self._impl.unregister(fd)
File "/usr/lib/python2.7/dist-packages/zmq/eventloop/ioloop.py", line 125, in unregister
return self._poller.unregister(fd)
File "/usr/lib/python2.7/dist-packages/zmq/sugar/poll.py", line 80, in unregister
idx = self._map.pop(socket)
KeyError: <zmq.sugar.socket.Socket object at 0x7f1679ae2db8>
[DEBUG   ] Initializing new AsyncZeroMQReqChannel for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506', 'aes')
[DEBUG   ] Initializing new SAuth for ('/etc/salt/pki/minion', 'dasalt', 'tcp://127.0.0.1:4506')
[DEBUG   ] LazyLoaded nested.output
local:
True

# Fixed code
def destroy(self):
    if hasattr(self, "stream"):
        # TODO: Optionally call stream.close() on newer pyzmq? It is broken on some.
        self.stream.socket.close()
        self.stream.io_loop.remove_handler(self.stream.socket)
        # set this to None, more hacks for messed up pyzmq
        self.stream.socket = None
        self.socket.close()
    self.context.term()