Skip to content

Conversation

@Angad-2002
Copy link

PR for #2876

Changes Made -

Services Updated:

  • CartesiaTTSService - Connection, message sending, and general exception handling
  • CartesiaSTTService - Connection failures and error message handling
  • ElevenLabsTTSService - Connection, disconnect, message sending, and general exception handling
  • DeepgramFluxSTTService - Connection and disconnect failures
  • DeepgramTTSService - Runtime exception handling (updated to use push_error())
  • AssemblyAISTTService - Connection and disconnect failures
  • RimeTTSService - Connection, disconnect, message sending, and general exception handling
  • RimeHttpTTSService - Runtime exception handling
  • AzureTTSService - Runtime exception handling

Key Features:

  • ErrorFrame objects emitted with fatal=False for graceful degradation
  • Consistent error handling patterns across all services
  • Comprehensive test coverage with pytest test suite
  • All pre-commit hooks passed (ruff formatting)

Testing

Added pytest test suite (tests/test_tts_stt_error_handling.py) that verifies:

  • ErrorFrame emission during connection failures
  • ErrorFrame emission during runtime failures
  • Proper error message content and fatality settings
  • Integration with on_pipeline_error event handler

@Angad-2002
Copy link
Author

@markbackman could you look into this PR?

except Exception as e:
logger.error(f"Failed to connect to AssemblyAI: {e}")
self._connected = False
await self.push_error(ErrorFrame(error=e, fatal=False))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use this as a pattern?

await self.push_error(ErrorFrame(error=f"{self} error: {e}, fatal=True"))

In this specific instance, is a connection error fatal?

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, re checking it I believe it is fatal = True, I am updating on the patterns to be followed

Copy link
Author

Choose a reason for hiding this comment

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

@markbackman should we also standardize the logger.error messages as logger.error(f"{self} exception: {e}")
or leave them as they are?

Copy link
Author

Choose a reason for hiding this comment

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

in some cases its not the format and in some places its there


except Exception as e:
logger.error(f"{self} exception: {e}")
await self.push_error(ErrorFrame(error=e, fatal=False))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also add an ErrorFrame to the Exception block starting in line 357?

@@ -0,0 +1,252 @@
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for offering this, but we need to create a pattern for this type of testing. For now, I'd say to just remove this and we can consider the best way to proceed.

Copy link
Author

Choose a reason for hiding this comment

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

noted, I would be removing this test

Copy link
Contributor

@markbackman markbackman left a comment

Choose a reason for hiding this comment

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

This generally looks good. I would recommend revisiting all STT and TTS classes to make sure that all Exceptions have ErrorFrames. Also, let's stick to the pattern of:

await self.push_error(ErrorFrame(error=f"{self} error: {e}", fatal=True/False))

Thanks so much for contributing this 🙏. I was actually just looking to do this on Friday, now that we have an on_pipeline_error event which benefits from these ErrorFrames being push. 🙌


Can you also do the following?

  • Rebase on main
  • Make sure code is linted (scripts/fix-ruff.sh or install pre-commit hook: uv run pre-commit install)
  • Add a changelog entry

@Angad-2002
Copy link
Author

Noted. I'll be making these changes

@Angad-2002 Angad-2002 force-pushed the feature/tts-stt-error-frames branch from fdf129c to bd654fa Compare October 22, 2025 07:09
@Angad-2002
Copy link
Author

@markbackman Can you check the updates made?

Changelog Entry
Rebased on main
Code linted

@Angad-2002
Copy link
Author

@markbackman I updated to add all the TTS and STT services

logger.error(f"Failed to connect to AssemblyAI: {e}")
logger.error(f"{self} exception: {e}")
self._connected = False
await self.push_error(ErrorFrame(error=f"{self} error: {e}", fatal=True))
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably not be fatal. A switcher processor could just switch to another STT service. In general, I believe we shouldn't really be using fatal=True unless for uncaught exceptions, which we handle somewhere else.

Copy link
Author

Choose a reason for hiding this comment

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

Thx for the comment so should we remove the fatal flag, through all the stt tts services again? and where to use True

except Exception as e:
logger.error(f"Error processing WebSocket message: {e}")
logger.error(f"{self} exception: {e}")
await self.push_error(ErrorFrame(error=f"{self} error: {e}", fatal=True))
Copy link
Contributor

Choose a reason for hiding this comment

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

Same.Don't make it fatal. I believe we should just remove fatal=X form this PR and use the default (which is False). Fatal means the whole bot should end.

Copy link
Author

Choose a reason for hiding this comment

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

So bascially you suggest we remove all exception frames from all stt and tts files

elif isinstance(frame, UserStoppedSpeakingFrame):
# Send finalize command to flush the transcription session
if self._connection and self._connection.state is State.OPEN:
await self._connection.send("finalize")
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we adding these 3 methods? These seem to conflict with other methods already defined (e.g. _disconnect).

Copy link
Author

Choose a reason for hiding this comment

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

I noticed that disconnect part, I would be removing this

@aconchillo
Copy link
Contributor

@Angad-2002 This is great, thank you for taking the time and do this. I've added some comments.

@Angad-2002
Copy link
Author

Angad-2002 commented Oct 22, 2025

Thx for the comments so what changes should be made overall?

@aconchillo
Copy link
Contributor

aconchillo commented Oct 22, 2025

Thx for the comments so what changes should be made overall?

Remove fatal=X from everywhere. Apologies if it was not clear 🙇

@aconchillo
Copy link
Contributor

Thx for the comments so what changes should be made overall?

Remove fatal=X from everywhere. Apologies if it was not clear 🙇

Also, there were some functions added. Not sure what the purpose of those were.

@markbackman markbackman self-requested a review October 22, 2025 22:53
@Angad-2002
Copy link
Author

I apologize for the duplication, actually I was rebasing on main, and merge conflicts led to duplicates

…detection

- Add ErrorFrame emission to all major TTS/STT services during initialization and runtime failures
- Services updated: Cartesia, ElevenLabs, Deepgram, AssemblyAI, Rime, Azure
- ErrorFrame objects emitted with fatal=False for graceful degradation
- Enables on_pipeline_error event handler to detect service failures programmatically
- Add comprehensive pytest test suite to verify ErrorFrame emission
- Fixes issue where services failed gracefully but didn't emit ErrorFrame objects

This allows developers to implement real-time error monitoring and alerting
using the on_pipeline_error event handler introduced in v0.0.90.
- Improves error handling consistency across all services
@Angad-2002 Angad-2002 force-pushed the feature/tts-stt-error-frames branch from 0a7bba7 to 68ea479 Compare October 23, 2025 06:14
@Angad-2002
Copy link
Author

@aconchillo I have rebased on main again and pushed new commit for flag removal and duplicate removal

@Angad-2002 Angad-2002 requested a review from aconchillo October 23, 2025 18:53
@Angad-2002
Copy link
Author

Angad-2002 commented Oct 24, 2025

@aconchillo @markbackman pls check the changes

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