```room = get_job_context().room async with Liv...
# ask-ai
a
Copy code
room = get_job_context().room

		async with LiveKitAPI() as lkapi:
			await lkapi.room.delete_room(DeleteRoomRequest(
				room=room
			))


   13:09:10.576 ERROR  livekit.agents     exception occurred while executing tool                                                                                               
                                           Traceback (most recent call last):                                                                                                    
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/agents/voice/generation.py", line 623, in _traceable_fnc_tool  
                                               val = await function_callable()                                                                                                   
                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                   
                                             File "/var/www/livekit-agent/tools/hangup.py", line 32, in sip_hangup                                                               
                                               await lkapi.room.delete_room(DeleteRoomRequest(                                                                                   
                                                                            ~~~~~~~~~~~~~~~~~^                                                                                   
                                                   room=room                                                                                                                     
                                                ^^^^^^^^^                                                                                                                        
                                               ))                                                                                                                                
                                               ^                                                                                                                                 
                                           TypeError: bad argument type for built-in operation
t
Thanks for reaching out, Ahron. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — that error is happening because you’re passing a Room object where the API expects a room name string. I’m responding to your trace complaining about a TypeError for the
delete_room(DeleteRoomRequest(...))
call. What to change • Use the room’s name string instead of the Room object. Quick fix (recommended):
Copy code
room = get_job_context().room

async with LiveKitAPI() as lkapi:
    await lkapi.room.delete_room(DeleteRoomRequest(
        room=room.name  # pass the name (string), not the Room object
    ))
Two convenient alternatives • Let the JobContext handle it for you:
Copy code
ctx = get_job_context()
await ctx.delete_room()  # uses the room name internally
• Call the API directly but still pass the name:
Copy code
from livekit import api

ctx = get_job_context()
async with api.LiveKitAPI() as lkapi:
    await lkapi.room.delete_room(api.DeleteRoomRequest(room=ctx.room.name))
If you want, share the output of: •
type(get_job_context().room)
and
get_job_context().room
(or
get_job_context().room.name
) — I can confirm what you’re getting and make sure the change will work in your environment.
a
that works. I also get an error when ending
Copy code
13:18:48.003 ERROR  livekit.agents     error while shutting down the job                                                                                                     
                                           Traceback (most recent call last):                                                                                                    
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/agents/ipc/job_proc_lazy_main.py", line 379, in _run_job_task  
                                               await asyncio.gather(*shutdown_tasks)                                                                                             
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/agents/job.py", line 452, in wrapper                           
                                               await callback()  # type: ignore                                                                                                  
                                               ^^^^^^^^^^^^^^^^                                                                                                                  
                                           TypeError: object NoneType can't be used in 'await' expression
t
Thanks — glad the room-name fix worked. You're now seeing a shutdown-time TypeError saying a None value is being awaited. I’ll explain why that happens and how to fix it, plus a couple safe patterns you can use. What this error means • During job shutdown LiveKit gathers and awaits the shutdown callbacks with
await asyncio.gather(*shutdown_tasks)
. • One of the items in that list is
None
(or otherwise not awaitable), so Python raises: "object NoneType can't be used in 'await' expression". Likely causes • You called
ctx.add_shutdown_callback(...)
with a variable that is
None
. • You added a non-async function (or a function that returns None instead of a coroutine) as a shutdown callback. • You conditionally built a callback and accidentally passed None when the condition was false. How to fix it • Only add actual coroutine callables to shutdown callbacks. Ensure the value you pass to
ctx.add_shutdown_callback
is an async function (callable that returns a coroutine when called) or a coroutine function reference. Quick checks to run 1. Search your code for every
ctx.add_shutdown_callback(...)
. 2. For each callback, verify: ◦ It is not None. ◦ It is an async function (defined with
async def
) or a callable that returns a coroutine. ◦ You are passing the function object (not the result of calling it). For example, pass
on_shutdown
not
on_shutdown()
. Safe patterns 1) Add only if present:
Copy code
if on_shutdown is not None:
    ctx.add_shutdown_callback(on_shutdown)
2) Ensure the callback is async:
Copy code
async def on_shutdown():
    # cleanup
    await some_cleanup()

ctx.add_shutdown_callback(on_shutdown)  # pass function, not call
3) Wrap optional cleanup into a guaranteed coroutine:
Copy code
def maybe_create_shutdown_task():
    if need_cleanup:
        async def _cleanup():
            await do_cleanup()
        return _cleanup
    return None

shutdown_cb = maybe_create_shutdown_task()
if shutdown_cb:
    ctx.add_shutdown_callback(shutdown_cb)
4) Defensive runtime check (useful for debugging):
Copy code
cb = possible_cb
if cb is None:
    logger.warning("Skipping None shutdown callback")
elif not asyncio.iscoroutinefunction(cb):
    logger.error("Shutdown callback is not async: %s", cb)
else:
    ctx.add_shutdown_callback(cb)
If you'd like, share the lines where you call
ctx.add_shutdown_callback(...)
(or the function that builds those callbacks). I can quickly scan them and point out exactly which callback is None or non-async. Sources: Job lifecycle | LiveKit Documentation
a
Copy code
14:23:43.025 WARNI… livekit.agents     failed to stream event to clients                                                                                                       
                                           Traceback (most recent call last):                                                                                                      
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/agents/voice/client_events.py", line 509, in _send_client_event  
                                               writer = await self._room.local_participant.stream_text(                                                                            
                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                            
                                               ...<2 lines>...                                                                                                                     
                                               )                                                                                                                                   
                                               ^                                                                                                                                   
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/rtc/participant.py", line 581, in stream_text                    
                                               await writer._send_header()                                                                                                         
                                             File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/rtc/data_stream.py", line 189, in _send_header                   
                                               raise ConnectionError(cb.send_stream_header.error)                                                                                  
                                           ConnectionError: engine: connection error: engine is closed                                                                             
                                         {"pid": 90470, "job_id": "AJ_VaiM7nGXqpBT", "room_id": "RM_ocjbtWCECAMC"}
Traceback (most recent call last):
  File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/agents/voice/client_events.py", line 509, in _send_client_event
    writer = await self._room.local_participant.stream_text(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    )
    ^
  File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/rtc/participant.py", line 581, in stream_text
    await writer._send_header()
  File "/var/www/livekit-agent/lk/lib/python3.13/site-packages/livekit/rtc/data_stream.py", line 189, in _send_header
    raise ConnectionError(cb.send_stream_header.error)
ConnectionError: engine: connection error: engine is closed
t
Thanks — I see the ConnectionError ("engine: connection error: engine is closed") that happens when the agent tries to stream events to clients while the underlying WebRTC engine has already been closed. I’ll walk through why this happens and give concrete, minimal changes you can make to stop it. What’s happening • The client events handler tries to call
local_participant.stream_text(...)
while the room/engine is already closed. • That produces
ConnectionError: engine: connection error: engine is closed
. • This is a race during shutdown: event emission still runs while the connection is being torn down. What you can do (in order of recommendation) 1) Ensure client-events are stopped before closing the connection • In your shutdown callback, stop any producers of events first, then close the client events handler, and only after that delete the room or close the session/engine. Example pattern:
Copy code
async def cleanup():
    # 1. stop anything that generates events (interrupt session, stop tasks)
    if hasattr(session, "interrupt"):
        session.interrupt()

    # 2. close client events handler (prevents further streaming attempts)
    if hasattr(session, "_client_events_handler") and session._client_events_handler:
        await session._client_events_handler.aclose()

    # 3. delete room / close API connections
    await api.LiveKitAPI().room.delete_room(api.DeleteRoomRequest(room=ctx.room.name))
2) Make event streaming resilient to a closed engine • Before attempting to stream, check that the room/engine is still connected. If not, skip the send. Example:
Copy code
if not getattr(self._room, "is_connected", lambda: False)():
    logger.debug("Room disconnected, skipping event stream")
    return
try:
    await self._send_client_event(event)
except ConnectionError as e:
    if "engine is closed" in str(e):
        logger.debug("Engine closed while sending event, ignoring")
    else:
        raise
3) Ensure callbacks you register are proper coroutines (to avoid other shutdown errors) • When you add shutdown callbacks with
ctx.add_shutdown_callback(...)
ensure you pass an async function (not None and not the result of calling it). Example:
Copy code
ctx.add_shutdown_callback(cleanup)  # pass function object, not cleanup()
4) Optional: suppress noisy logs during shutdown (if the error is harmless for you) • If this happens only during shutdown and you can’t easily reorder cleanup, temporarily lower the log level for that module:
Copy code
import logging
logging.getLogger("livekit.agents.voice.client_events").setLevel(logging.ERROR)
Use this only if you’re confident the condition is harmless in your flow. What I can check for you • If you share the shutdown callback(s) and where you register or create the client events handler (the code around
ctx.add_shutdown_callback(...)
and session start/stop), I can point to the exact line that should be reordered or guarded. • If you prefer, paste the code that emits events so I can suggest the precise guard to add. If you want, start by pasting your shutdown callback and where you create/attach the client events handler — I’ll mark exactly what to change.