Summary
After upgrading to livekit-agents 1.8.4 (which pins livekit==1.1.20), every job shutdown at the end of a voice session prints several AssertionErrors from FfiHandle.__del__:
Exception ignored in: <function FfiHandle.__del__ at 0x...>
Traceback (most recent call last):
File ".../site-packages/livekit/rtc/_ffi_client.py", line 77, in __del__
self.dispose()
File ".../site-packages/livekit/rtc/_ffi_client.py", line 99, in dispose
assert dropped
^^^^^^^
AssertionError:
They appear right after the job's shutdown callbacks run (after UsageCollector summary logging and http_session(): closing the httpclient ctx), six times in our case. The process otherwise shuts down normally — it looks like log noise, but it means a Python FfiHandle is being garbage-collected for a handle the native side has already released.
We did not see this on livekit 1.1.8 (with livekit-agents 1.5.17), although the same assert existed in FfiHandle.dispose() there.
Environment
livekit 1.1.20, livekit-agents 1.8.4, livekit-plugins-google 1.8.4
- Python 3.12, macOS (arm64)
- Worker started with
lk agent dev; session: AgentSession(llm=google.realtime.RealtimeModel(model="gemini-3.8-live")), browser client (livekit-client 2.22.3) receiving transcriptions; the user ends the call from the browser (room.disconnect()).
What we looked at
FfiHandle.dispose() sets _disposed = True before dropping, so an explicit dispose() followed by GC can't double-drop — the failing drops come from __del__ on handles that were never disposed from Python but are already gone natively.
- 1.1.20 newly wraps data stream writer handles in
FfiHandle (_register_open / _unregister_open in data_stream.py, _open_stream_writers in participant.py, _dispose_open_stream_writers in room.py). Since agents publish transcriptions over text streams, we suspect writers (or other handles) that the native side frees together with the room, and that Python only collects after that — but we haven't confirmed which handle type is involved.
Expected
No assertion output at shutdown; or, if a native-side release before Python GC is legitimate, __del__ should not assert on it.
Happy to test a fix or add logging (e.g. the handle type in FfiHandle.__repr__) if that helps narrow it down.
Summary
After upgrading to
livekit-agents1.8.4 (which pinslivekit==1.1.20), every job shutdown at the end of a voice session prints severalAssertionErrors fromFfiHandle.__del__:They appear right after the job's shutdown callbacks run (after
UsageCollectorsummary logging andhttp_session(): closing the httpclient ctx), six times in our case. The process otherwise shuts down normally — it looks like log noise, but it means a PythonFfiHandleis being garbage-collected for a handle the native side has already released.We did not see this on
livekit1.1.8 (withlivekit-agents1.5.17), although the sameassertexisted inFfiHandle.dispose()there.Environment
livekit1.1.20,livekit-agents1.8.4,livekit-plugins-google1.8.4lk agent dev; session:AgentSession(llm=google.realtime.RealtimeModel(model="gemini-3.8-live")), browser client (livekit-client2.22.3) receiving transcriptions; the user ends the call from the browser (room.disconnect()).What we looked at
FfiHandle.dispose()sets_disposed = Truebefore dropping, so an explicitdispose()followed by GC can't double-drop — the failing drops come from__del__on handles that were never disposed from Python but are already gone natively.FfiHandle(_register_open/_unregister_openindata_stream.py,_open_stream_writersinparticipant.py,_dispose_open_stream_writersinroom.py). Since agents publish transcriptions over text streams, we suspect writers (or other handles) that the native side frees together with the room, and that Python only collects after that — but we haven't confirmed which handle type is involved.Expected
No assertion output at shutdown; or, if a native-side release before Python GC is legitimate,
__del__should not assert on it.Happy to test a fix or add logging (e.g. the handle type in
FfiHandle.__repr__) if that helps narrow it down.