Python SDK Bad file descriptor with asyncio

Hi,

we've changed one of our software deployments to be Zitified instead of using Ziti Edge Tunnelers as before. Pretty cool as we can deploy via Ziti in Github Actions now! :smiling_face_with_sunglasses:
Unfortunately we are getting the below errors which we didn't get while using ZET. Any ideas?

We're using openziti==1.5.0, Controller v1.6.12

2026-01-05 19:10:40,967 - ERROR - Exception in callback _SelectorTransport._add_reader(21, <bound method..., bufsize=0>>>)
handle: <Handle _SelectorTransport._add_reader(21, <bound method..., bufsize=0>>>)>
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 282, in _add_reader
    key = self._selector.get_key(fd)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/selectors.py", line 192, in get_key
    raise KeyError("{!r} is not registered".format(fileobj)) from None
KeyError: '21 is not registered'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 928, in _add_reader
    self._loop._add_reader(fd, callback, *args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 284, in _add_reader
    self._selector.register(fd, selectors.EVENT_READ,
  File "/usr/local/lib/python3.12/selectors.py", line 359, in register
    self._selector.register(key.fd, poller_events)
OSError: [Errno 9] Bad file descriptor
2026-01-05 19:10:40,968 - ERROR - Exception in callback _SelectorTransport._add_reader(23, <bound method..., bufsize=0>>>)
handle: <Handle _SelectorTransport._add_reader(23, <bound method..., bufsize=0>>>)>
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 282, in _add_reader
    key = self._selector.get_key(fd)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 928, in _add_reader
    self._loop._add_reader(fd, callback, *args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 284, in _add_reader
    self._selector.register(fd, selectors.EVENT_READ,
  File "/usr/local/lib/python3.12/selectors.py", line 359, in register
    self._selector.register(key.fd, poller_events)
OSError: [Errno 9] Bad file descriptor
2026-01-05 19:10:40,972 - ERROR - Exception in callback _SelectorTransport._add_reader(29, <bound method..., bufsize=0>>>)
handle: <Handle _SelectorTransport._add_reader(29, <bound method..., bufsize=0>>>)>
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 282, in _add_reader
    key = self._selector.get_key(fd)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/selectors.py", line 192, in get_key
    raise KeyError("{!r} is not registered".format(fileobj)) from None
KeyError: '29 is not registered'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 928, in _add_reader
    self._loop._add_reader(fd, callback, *args)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 284, in _add_reader
    self._selector.register(fd, selectors.EVENT_READ,
  File "/usr/local/lib/python3.12/selectors.py", line 359, in register
    self._selector.register(key.fd, poller_events)
OSError: [Errno 9] Bad file descriptor

The code we're using to monkeypatch:

import os
import tempfile

import openziti


class OpenZitiConnection:
    def __init__(self):
        self._identity_tmpfile = None

    def load_ziti_identity_from_string(self, identity_json_str: str):
        self._identity_tmpfile = tempfile.NamedTemporaryFile(mode="w+", delete=False)
        self._identity_tmpfile.write(identity_json_str)
        self._identity_tmpfile.flush()

        ztx = openziti.load(self._identity_tmpfile.name)
        return ztx

    def init_ziti_from_config(self, host: str, port: str) -> None:
        ztx = self.load_ziti_identity_from_string(
            os.environ.get("USECASE_DEPLOYMENT_ZITI_IDENTITY_JSON")
        )

        bindings = {
            (host, port): {
                "ztx": ztx,
            }
        }

        openziti.monkeypatch(bindings=bindings)

    def init_ziti_from_config_multi(self, bindings: dict) -> None:
        ztx = self.load_ziti_identity_from_string(
            os.environ.get("USECASE_DEPLOYMENT_ZITI_IDENTITY_JSON")
        )

        for addr in bindings:
            bindings[addr]["ztx"] = ztx

        openziti.monkeypatch(bindings=bindings)

Thanks
Dominik