good day, i have found that trackma is crashing on me a lot. i figured out that its the discord presence hook thats doing that. it seems its attempting to open too many sockets without closing them before retrying. i figured that out on my own but i used ai to write it up as a nicer looking right up,
presence hook leaks file descriptors, crashes trackma-qt
Been using the presence hook for a while and noticed trackma-qt would crash after running for some time, quicker when Discord wasn't open.
What's happening
Every second, _reconnect() creates a new Client object and calls start() on it. If Discord isn't available it raises an exception (caught), and tries again next second.
When start() fails because Discord isn't running, sock_writer is never set — it stays None. So close() throws AttributeError on sock_writer.close(), which gets swallowed, and loop.close() is never called.
Every Client() instantiation creates a brand new asyncio event loop via pypresence's get_event_loop(). Each of those loops holds internal epoll/pipe file descriptors. Without loop.close() being called, those FDs accumulate every second until the process hits the OS limit (1024 by default on Linux).
Once the limit is hit, socket.socket() throws OSError: [Errno 24] Too many open files. That error isn't in _errors so it propagates uncaught, kills the thread, and then GLib starts failing to create its own pipes which takes down the whole process with SIGTRAP.
Crash log
Traceback (most recent call last):
File "/usr/lib/python3.14/threading.py", line 1082, in _bootstrap_inner
self._context.run(self.run)
~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/home/martym/.config/trackma/hooks/presence.py", line 87, in run
self._reconnect()
~~~~~~~~~~~~~~~^^
File "/home/martym/.config/trackma/hooks/presence.py", line 123, in _reconnect
self._rpc.start()
~~~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/site-packages/pypresence/client.py", line 284, in start
self.loop.run_until_complete(self.handshake())
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/asyncio/base_events.py", line 719, in run_until_complete
return future.result()
~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/site-packages/pypresence/baseclient.py", line 145, in handshake
ipc_path = get_ipc_path(self.pipe)
File "/usr/lib/python3.14/site-packages/pypresence/utils.py", line 65, in get_ipc_path
and test_ipc_path(entry.path)
~~~~~~~~~~~~~^^^^^^^^^^^^
File "/usr/lib/python3.14/site-packages/pypresence/utils.py", line 28, in test_ipc_path
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/socket.py", line 236, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 24] Too many open files
(process:3080659): GLib-ERROR **: 21:47:56.746: Creating pipes for GWakeup: Too many open files
fish: Job 1, 'trackma-qt -d &' terminated by signal SIGTRAP (Trace or breakpoint trap)
Fix
Instead of going through _rpc.close() (which fails before reaching loop.close() on a never-connected client), close the loop directly:
def _reconnect(self):
if not self._enabled:
try:
if self._rpc is not None:
try:
if not self._rpc.loop.is_closed():
self._rpc.loop.close()
except Exception:
pass
self._rpc = Client(self._client_id)
self._rpc.start()
self._enabled = True
except self._errors:
self._enabled = False
Tested by monitoring /proc/<pid>/fd with Discord closed — FD count stays flat and actually decreases slightly as GC runs, instead of climbing to the limit.
Environment
- trackma-qt v0.10.3
- Python 3.14
- pypresence latest
- Linux (CachyOS)
good day, i have found that trackma is crashing on me a lot. i figured out that its the discord presence hook thats doing that. it seems its attempting to open too many sockets without closing them before retrying. i figured that out on my own but i used ai to write it up as a nicer looking right up,
presence hook leaks file descriptors, crashes trackma-qt
Been using the presence hook for a while and noticed trackma-qt would crash after running for some time, quicker when Discord wasn't open.
What's happening
Every second,
_reconnect()creates a newClientobject and callsstart()on it. If Discord isn't available it raises an exception (caught), and tries again next second.When
start()fails because Discord isn't running,sock_writeris never set — it staysNone. Soclose()throwsAttributeErroronsock_writer.close(), which gets swallowed, andloop.close()is never called.Every
Client()instantiation creates a brand new asyncio event loop via pypresence'sget_event_loop(). Each of those loops holds internal epoll/pipe file descriptors. Withoutloop.close()being called, those FDs accumulate every second until the process hits the OS limit (1024 by default on Linux).Once the limit is hit,
socket.socket()throwsOSError: [Errno 24] Too many open files. That error isn't in_errorsso it propagates uncaught, kills the thread, and then GLib starts failing to create its own pipes which takes down the whole process withSIGTRAP.Crash log
Fix
Instead of going through
_rpc.close()(which fails before reachingloop.close()on a never-connected client), close the loop directly:Tested by monitoring
/proc/<pid>/fdwith Discord closed — FD count stays flat and actually decreases slightly as GC runs, instead of climbing to the limit.Environment