lively-horse-90722
02/25/2026, 12:11 PMfailed to publish transcription\nTraceback (most recent call last):\n File \"/app/.venv/lib/python3.12/site-packages/livekit/agents/voice/room_io/_output.py\", line 383, in capture_text\n tmp_writer = await self._create_text_writer()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/.venv/lib/python3.12/site-packages/livekit/agents/voice/room_io/_output.py\", line 355, in _create_text_writer\n return await self._room.local_participant.stream_text(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/.venv/lib/python3.12/site-packages/livekit/rtc/participant.py\", line 578, in stream_text\n await writer._send_header()\n File \"/app/.venv/lib/python3.12/site-packages/livekit/rtc/data_stream.py\", line 189, in _send_header\n raise ConnectionError(cb.send_stream_header.error)\nConnectionError: engine: connection error: engine is closed"tall-airline-16756
02/25/2026, 12:12 PMtall-airline-16756
02/25/2026, 12:12 PMstream_text(). I’ll walk through what that means and the most likely fixes, then ask a couple quick questions so I can narrow the root cause.
What this error means
• The SDK attempted to open a data/text stream to the room (via stream_text()), but the underlying WebRTC engine (the room/participant connection) had already shut down. The SDK fails when it tries to send the stream header because the engine is closed.
What commonly causes this and how to fix it
1. Publishing after session shutdown
◦ Cause: Your code is trying to send transcriptions while the agent session or room is being closed.
◦ Fix: Ensure all transcription publishing finishes before calling `shutdown()`/`aclose()`. If you need the session to drain outstanding work, use a graceful shutdown pattern (wait for in-flight tasks to finish or call a drain option before closing).
1. Participant left or room closed early
◦ Cause: The participant left or the room ended while you were still sending text.
◦ Fix: Detect participant/room disconnects and stop sending. Capture and publish final transcriptions before the participant leaves or avoid starting long-running sends when disconnect is likely.
1. Background tasks continue after disconnect
◦ Cause: LLM or transcription streaming tasks keep running after the room is closed and try to write to the text stream.
◦ Fix: Cancel or check cancellation tokens for background streams. Before calling stream_text() or sending chunks, check session/room connection state and abort if closed.
1. Network/connection instability
◦ Cause: WebRTC connection lost (timeouts, network errors) and engine closed.
◦ Fix: Listen for connection state changes, and do not attempt writes once you detect disconnect. Optionally retry from a fresh connection if appropriate.
Practical checks and small code guards to add
• Check connection state before sending:
if not session.room or session.room.connection_state != rtc.ConnectionState.CONN_CONNECTED:
logger.warning("Cannot publish transcription: room not connected")
return
• Stop streaming on shutdown or participant leave:
if session.closed:
break # avoid writes after closed
• Wrap send attempts with try/except to log and avoid unhandled exceptions:
try:
await participant.stream_text(...)
except ConnectionError as e:
<http://logger.info|logger.info>("Stream write failed: engine closed; aborting transcription send")
Recommended debugging steps
1. Add logging around your session lifecycle: when the room opens, when it closes, and when you call stream_text().
2. Identify whether shutdown or a disconnect event happens just before the first stream_text() call.
3. Confirm whether any background LLM/transcription task continues after the session closes.
4. If possible, reproduce locally and capture the sequence: participant leaves? you call shutdown? LLM still streaming?
Two quick questions to narrow it down
1. Do you explicitly call `shutdown()`/`aclose()` (or similar) when the participant leaves or at the end of your flow?
2. Is the transcription being published from a background/long-running task (LLM streaming) that may still be producing output after the session closes?
If you share brief answers (and — if convenient — where in your flow you call session shutdown or where the transcription writer is created), I’ll suggest targeted code changes or a small pattern to ensure transcriptions are only attempted while the engine is active.
Sources: Text and transcriptions | LiveKit Documentation | Agent session | LiveKit Documentation | How to build an agent with speech-to-text input and text-only output | Live... | Job lifecycle | LiveKit Documentation | Understanding the STATE_MISMATCH Disconnect Reason | LiveKit