From 35f52f70ab27c19a062f6628970cff6657e330cf Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Tue, 24 Mar 2026 13:42:01 -0400 Subject: [PATCH] Fix TTS flush creating phantom contexts on providers like ElevenLabs When an interruption arrives before any LLM text reaches run_tts, the turn context ID exists but was never registered via create_audio_context. Calling flush_audio for this unregistered context sends a message to the provider (e.g. ElevenLabs) with a context_id it has never seen, which implicitly creates a server-side context that is never closed. After enough rapid interruptions these phantom contexts accumulate and exceed the providers limit (ElevenLabs: 5 simultaneous contexts, 1008 policy violation). Guard the flush call with audio_context_available so it only fires when the context was actually opened. Fixes #4114 --- src/pipecat/services/tts_service.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pipecat/services/tts_service.py b/src/pipecat/services/tts_service.py index 6d475bdc2..f6f4983ec 100644 --- a/src/pipecat/services/tts_service.py +++ b/src/pipecat/services/tts_service.py @@ -682,7 +682,12 @@ class TTSService(AIService): await self.remove_audio_context(self._turn_context_id) # Flush any pending audio so the TTS service closes the current context. - await self.flush_audio(context_id=self._turn_context_id) + # Only flush if the context was actually opened (text reached run_tts). + # When an interruption arrives before any text flows, the turn context ID + # exists but was never registered via create_audio_context, so flushing + # would send a message for a context the provider never opened. + if self._turn_context_id and self.audio_context_available(self._turn_context_id): + await self.flush_audio(context_id=self._turn_context_id) # Reset the turn context ID self._turn_context_id = None