```{"message": "error decoding audio\nTraceback (m...
# ask-ai
f
Copy code
{
  "message": "error decoding audio\nTraceback (most recent call last):\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/utils/codecs/decoder.py\", line 168, in _decode_loop\n container = av.open(\n self._input_buf,\n ...<11 lines>...\n },\n )\n File \"av/container/core.pyx\", line 482, in av.container.core.open\n File \"av/container/core.pyx\", line 298, in av.container.core.Container.__cinit__\n File \"av/container/core.pyx\", line 318, in av.container.core.Container.err_check\n File \"av/error.pyx\", line 424, in av.error.err_check\nav.error.EOFError: [Errno 541478725] End of file: '<none>'",
  "level": "ERROR",
  "name": "livekit.agents",
  "exc_info": "Traceback (most recent call last):\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/utils/codecs/decoder.py\", line 168, in _decode_loop\n container = av.open(\n self._input_buf,\n ...<11 lines>...\n },\n )\n File \"av/container/core.pyx\", line 482, in av.container.core.open\n File \"av/container/core.pyx\", line 298, in av.container.core.Container.__cinit__\n File \"av/container/core.pyx\", line 318, in av.container.core.Container.err_check\n File \"av/error.pyx\", line 424, in av.error.err_check\nav.error.EOFError: [Errno 541478725] End of file: '<none>'",
  "room": "44dbe75c-0d19-416b-b982-9b3de1433512",
  "pid": 13098,
  "job_id": "AJ_2rLj358sunZM",
  "room_id": "RM_xrNinqecKwiq",
  "timestamp": "2026-02-18T23:23:08.000607+00:00"
}
t
Thanks for reaching out, Vishalli. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m sorry you ran into this EOFError while decoding audio. I’m responding to the error you shared:
av.error.EOFError: [Errno 541478725] End of file: '<none>'
raised from the LiveKit Agents decoder when calling
av.open()
on the input buffer. What this means (brief) • The decoder attempted to open or read media from an input buffer but found no usable data — an end-of-file condition on an empty or incomplete buffer. • Common causes: the incoming audio stream ended unexpectedly or never contained audio, the buffer was already consumed/cleared before decoding, or a disruption in the media pipeline (e.g., a track ended or a network interruption). What you can check next • When does the error occur? ◦ During live playback, when starting a transcription job, after a participant leaves, or at another specific point? • Consistency ◦ Does this happen every time for the same room/job or only intermittently? • Agent lifecycle and buffer handling ◦ Confirm the code path that writes audio into the buffer passed to the decoder and ensure the buffer contains data before calling
av.open()
. ◦ Ensure you’re not closing or emptying the buffer earlier in the pipeline or reusing a buffer that’s already been consumed. • Media lifecycle events ◦ Check if the track has signaled ended/stopped immediately before the decode attempt. If so, guard the decoder call with a check that the track is still active and data is available. • Recent changes ◦ Any recent code changes around media capture, buffering, or track lifecycle handling? • Versions & environment ◦ Which versions of
livekit-agents
and
pyav
(or
av
) are you running? ◦ Runtime environment (Python version, OS/container) can also help. Suggested quick mitigations • Add a pre-check to ensure the input buffer has data before calling
av.open()
and log the buffer size/length when the call fails. • Add retry logic or a graceful fallback when EOF is encountered (for transient network interruptions). • If the error correlates with a track ending, skip decode attempts once the track end is observed. If you want, please share the following so I can give a more specific recommendation: • The context where this happens (playback, transcription, recording, etc.). • Whether it’s reproducible and the sequence of actions to reproduce. •
livekit-agents
and
pyav
(
av
) versions. • A short snippet showing how the input buffer is created/populated and where you call the decoder (sanitized if needed). I’ll walk through the logs/snippet and suggest targeted fixes or code changes once I have that info.
f
{"message": "failed to publish transcription\nTraceback (most recent call last):\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/voice/room_io/_output.py\", line 441, in capture_text\n tmp_writer = await self._create_text_writer()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/voice/room_io/_output.py\", line 413, in _create_text_writer\n return await self._room.local_participant.stream_text(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n ...<3 lines>...\n )\n ^\n File \"/app/.venv/lib/python3.13/site-packages/livekit/rtc/participant.py\", line 578, in stream_text\n await writer._send_header()\n File \"/app/.venv/lib/python3.13/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", "level": "WARNING", "name": "livekit.agents", "exc_info": "Traceback (most recent call last):\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/voice/room_io/_output.py\", line 441, in capture_text\n tmp_writer = await self._create_text_writer()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/app/.venv/lib/python3.13/site-packages/livekit/agents/voice/room_io/_output.py\", line 413, in _create_text_writer\n return await self._room.local_participant.stream_text(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n ...<3 lines>...\n )\n ^\n File \"/app/.venv/lib/python3.13/site-packages/livekit/rtc/participant.py\", line 578, in stream_text\n await writer._send_header()\n File \"/app/.venv/lib/python3.13/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", "room": "39ecacf0-4174-4845-a90e-2a11ed223091", "pid": 77118, "job_id": "AJ_WBkooQKtcGYP", "room_id": "RM_NsCm3hk3BEV3", "timestamp": "2026-02-19T040733.103220+00:00"}
t
Thanks — I’m sorry you’re hitting both the EOFError when decoding audio and the ConnectionError when publishing transcriptions. I’m responding to the new log you sent about: • ConnectionError:
engine: connection error: engine is closed
thrown from
stream_text()
when attempting to publish transcription text. What this means (short) • The agent is trying to send text after the underlying WebRTC engine (the room/peer connection) has already been closed. Once the engine is closed, attempts to open a data stream or send headers will raise a ConnectionError. Immediate checks I recommend • Where in your flow this happens: Is it after a participant leaves, during agent shutdown, or after a network interruption? • Reproducibility: Is it consistent for the same room/job or intermittent? • Versions: Which
livekit-agents
and Python `av`/`pyav` versions are you using? • Code path: A short sanitized snippet showing how/when you call
stream_text()
(or the surrounding lifecycle logic) will help pinpoint the issue. Practical fixes to prevent the error 1) Check connection state before sending • Ensure the room/engine is still connected before calling
stream_text()
. Example pattern:
Copy code
if not (self.session and self.session._room and self.session._room.engine.is_connected):
    logger.warning("Cannot publish transcription: room connection is closed")
    return
await self.session._room.local_participant.stream_text(content=text, topic="lk.transcription")
2) Stop publishing when room is closing • Subscribe to room/engine lifecycle events and cancel or skip publishing tasks when you observe disconnection/close. 3) Drain/commit pending work on shutdown • Before closing the session/room, commit any pending transcripts and allow in-flight audio/text tasks to finish:
Copy code
await self.session.commit_user_transcript()
await self.session.output.audio.drain_speech(wait_for_playout=True)
await self.session.close()
4) Add robust error handling and optional retry • Catch ConnectionError around
stream_text()
and either skip or retry with backoff only if the engine is still connected. Example retry skeleton:
Copy code
for attempt in range(max_retries):
    if not self.session._room.engine.is_connected:
        break
    try:
        await self.session._room.local_participant.stream_text(content=text)
        break
    except ConnectionError:
        await asyncio.sleep(0.5 * (attempt + 1))
Longer-term safeguards • Consider
auto_end_on_last_participant_left=False
if you need the agent to keep the room alive after humans leave. • Log connection state transitions so you can correlate when publishes are attempted vs when the engine closes. If you want, share any of the following and I’ll provide a targeted fix: • The exact sequence that leads to the error (e.g., participant left → agent tried to publish). • The snippet where you create/populate the transcription writer and call
stream_text()
. •
livekit-agents
and
pyav
(
av
) versions and whether these errors appear together or separately. I can then suggest a minimal code change or show where to add lifecycle guards to stop attempts to publish after the engine is closed. Sources: client-sdk-js | livekit/livekit_composite | DeepWiki | Server lifecycle | LiveKit Documentation
f
other issue await session.start( agent=agent, room=ctx.room, room_input_options=RoomInputOptions(noise_cancellation=noise_cancellation.BVCTelephony()), room_output_options=RoomOutputOptions(transcription_enabled=True), ) bot is not interupting
t
Thanks — I see you’re calling
session.start(...)
with
room_input_options
and
room_output_options
and the bot isn’t interrupting. I’m responding to that specific issue. Root cause • The parameter names are incorrect. The session.start API expects
input_options
and
output_options
. Using
room_input_options
and
room_output_options
means your intended settings are ignored and the session runs with defaults, which can prevent interruption behavior you expect. What to change • Update the call to use the correct parameter names:
Copy code
await session.start(
    agent=agent,
    room=ctx.room,
    input_options=RoomInputOptions(noise_cancellation=noise_cancellation.BVCTelephony()),
    output_options=RoomOutputOptions(transcription_enabled=True),
)
Other checks to ensure interruptions work • Confirm
allow_interruptions=True
for the AgentSession (it’s True by default). • Verify
min_interruption_duration
is low enough (default is 0.5s); reduce it if brief user speech should interrupt. • Make sure VAD/turn-detection is configured appropriately for your audio (telephony vs. wideband). If noise cancellation is very aggressive, try disabling it briefly to rule out suppressed speech. • Subscribe to room/turn events and log voice activity so you can see when the agent thinks a user is speaking vs when it’s speaking. If you’d like, share: • A short snippet of your session/agent configuration (sanitized), • Whether you’re using a pipeline or LLM-based agent, • Any logs showing VAD/turn events, and I’ll suggest the minimal config changes to make interruption reliable. Sources: Choosing the right noise cancellation for your agent | LiveKit | VAD and turn detection configuration guide | LiveKit | Turns overview | LiveKit Documentation | Interrupt User | LiveKit Documentation | How to build an agent with speech-to-text input and text-only output | Live...
f
min_interruption_words=2, serdata=dispatch, vad=ctx.proc.userdata["vad"], turn_detection="stt", llm=llm, stt=stt, tts=tts, preemptive_generation=True, min_interruption_words=2, # resume_false_interruption=True, min_endpointing_delay=0.4,
t
Thanks — you’ve shared your agent config snippet (with
turn_detection="stt"
,
min_interruption_words=2
,
preemptive_generation=True
,
min_endpointing_delay=0.4
, etc.). I’ll respond to that specific snippet and why the bot might still not be interrupting. Quick summary of how this config behaves •
turn_detection="stt"
uses the STT endpointing results to decide turns. That means interruptions are detected based on transcribed words and endpoint signals from STT rather than a separate turn-detector model. •
min_interruption_words=2
requires at least two transcribed words from the user before the system treats input as an interruption (this is valid and only used when STT is enabled). •
min_endpointing_delay=0.4
makes the agent wait 0.4s before treating a user turn as complete — lower values make responsiveness faster. •
preemptive_generation=True
helps the agent prepare replies earlier, but doesn’t itself guarantee it will drop speech when interrupted. Why interruptions may still not occur • Relying on STT-only turn detection can be less responsive than using a VAD/turn-detector plugin. If STT latency or segmentation delays occur, the agent may miss short interruption windows. •
min_interruption_words=2
will ignore very brief interruptions (one-word interjections). If users say short phrases, they won’t trigger an interruption. • Aggressive noise cancellation or VAD settings may suppress user speech so it never reaches STT as two words. • If the session or TTS call has interruptions disabled (e.g.,
allow_interruptions=False
on the session/reply/tts call), interruption requests will be ignored. • If your code is still using incorrect parameter names when calling
session.start()
(e.g.,
room_input_options
/
room_output_options
), the intended options may not be applied. Recommended checks and small changes to try 1) Confirm correct session.start parameter names • Use
input_options
and
output_options
— otherwise your configured options get ignored. 2) Add (or ensure) a VAD/turn-detector plugin alongside STT • VAD + STT improves responsiveness. When using STT-based endpointing, adding a VAD plugin makes interruption detection quicker and more reliable. 3) Temporarily lower
min_interruption_words
• Try
min_interruption_words=0
or
1
to see if short user interjections trigger interruptions. 4) Keep
min_endpointing_delay
conservative • 0.4s is reasonable; if you need faster reaction, test slightly lower values, but avoid too-low values that create false positives. 5) Verify
allow_interruptions
is enabled • Ensure the AgentSession, TTS/reply calls, and any per-reply options permit interruption (it’s True by default, but confirm no explicit override). 6) Test without noise cancellation briefly • Disable
noise_cancellation
to rule out suppression of user speech. If interruption improves, tune or swap the noise model. 7) Log events to debug • Log VAD activity, STT interim/final results, and agent state transitions. That will show whether user speech reached STT and whether the agent received an interruption trigger. Minimal experiment to isolate the issue • Start a session with: ◦
input_options
including a VAD plugin ◦
turn_detection="stt"
◦
min_interruption_words=0
(for testing) ◦
min_endpointing_delay=0.4
◦ no noise cancellation • Record logs: VAD on/off, STT partial/final transcripts, when TTS starts/stops, and any interruption events. If you want, paste a short sanitized snippet showing: • Your
session.start(...)
call (confirming you use
input_options
/
output_options
) • How you configure VAD or STT objects • Any explicit
allow_interruptions
settings I’ll review it and suggest the minimal config tweaks to make interruptions reliable for your use case. Sources: Turns overview | LiveKit Documentation | VAD and turn detection configuration guide | LiveKit | LiveKit turn detector plugin | LiveKit Documentation | Agents - Field Guides | LiveKit