Skip to content

fix(elevenlabs): propagate non-retryable STT errors instead of swallowing them - #7978

Closed
Speedyzyzz wants to merge 3 commits into
livekit:mainfrom
Speedyzyzz:fix/elevenlabs-stt-fatal-error-zombie-sessions
Closed

Speedyzyzz wants to merge 3 commits into
livekit:mainfrom
Speedyzyzz:fix/elevenlabs-stt-fatal-error-zombie-sessions

Conversation

@Speedyzyzz

Copy link
Copy Markdown

Problem

When the ElevenLabs STT WebSocket server sends a quota_exceeded or auth_error frame, the existing except Exception handler in _recv_task silently swallowed the error. This left the WebSocket stuck in a half-open receive loop that hung indefinitely — producing a zombie agent session with no audio output, no transcript events, and no visible error surfaced to the caller.

Two root causes combine to produce the hang:

  1. APIError swallowed by except Exception: _handle_error raises APIConnectionError (a subclass of APIError), but the outer except Exception in _recv_task catches and logs it instead of letting it escape. The task then blocks on the next ws.receive() call with no server message ever arriving.

  2. Non-retryable errors marked retryable: _handle_error previously raised APIConnectionError() without a retryable flag, which defaults to True. The reconnect loop therefore kept retrying quota_exceeded and auth_error failures that can never recover without operator action.

Fix

  • Re-raise APIError before the generic except Exception handler in _recv_task, so fatal server errors escape the task and are visible to the caller.
  • In _handle_error, set retryable=False for quota_exceeded and auth_error message types, and retryable=True (explicit) for all other server error frames.

Tests

Added test_recv_task_propagates_api_error_on_error_message in tests/test_plugin_elevenlabs_stt.py. The test feeds a quota_exceeded frame into a live SpeechStream via a stub WebSocket and asserts that APIConnectionError is raised within 1 second rather than hanging.

  • 109/109 tests in tests/test_plugin_elevenlabs_stt.py pass.
  • ruff check and ruff format are clean.

…wing them

When the ElevenLabs WebSocket STT server sends a quota_exceeded or auth_error
frame, the previous except Exception handler in _recv_task silently swallowed
the error and left the WebSocket in a half-open receive loop that hung
indefinitely — producing a zombie agent session with no audio output and no
visible error.

Two changes to close this:

1. Re-raise APIError before the generic except Exception handler so that any
   APIError (including the APIConnectionError raised by _handle_error) escapes
   _recv_task and is seen by the caller rather than being logged and suppressed.

2. Mark quota_exceeded and auth_error as non-retryable (retryable=False) in
   _handle_error. Previously every _handle_error path raised
   APIConnectionError() without a retryable flag, which defaults to True,
   causing the reconnect loop to keep retrying a credential or quota failure
   that will never recover.

Together these ensure a fatal server error cleanly terminates the stream
instead of spinning forever.

Tests: added test_recv_task_propagates_api_error_on_error_message in
tests/test_plugin_elevenlabs_stt.py, which feeds a quota_exceeded frame into
a live SpeechStream and asserts that APIConnectionError is raised within 1 s.
109/109 tests pass, ruff clean.
Copilot AI balanced review requested due to automatic review settings October 20, 2026 08:51
@Speedyzyzz
Speedyzyzz requested a review from a team as a code owner October 20, 2026 08:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

devin-ai-integration[bot]

This comment was marked as resolved.

@longcw

longcw commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

fixed by #7287

@longcw longcw closed this Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants