From 08b2365244dd3447cad229925b018dd2afc46fdc Mon Sep 17 00:00:00 2001 From: Filipi Fuchter Date: Tue, 18 Nov 2025 17:50:47 -0300 Subject: [PATCH] Starting to refactor how we are handling the errors. --- src/pipecat/frames/frames.py | 1 + src/pipecat/processors/frame_processor.py | 45 ++++++++++++++++++++--- src/pipecat/services/fish/tts.py | 3 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/pipecat/frames/frames.py b/src/pipecat/frames/frames.py index ddb4e5a14..990f0aa97 100644 --- a/src/pipecat/frames/frames.py +++ b/src/pipecat/frames/frames.py @@ -812,6 +812,7 @@ class ErrorFrame(SystemFrame): error: str fatal: bool = False processor: Optional["FrameProcessor"] = None + exception: Optional[Exception] = None def __str__(self): return f"{self.name}(error: {self.error}, fatal: {self.fatal})" diff --git a/src/pipecat/processors/frame_processor.py b/src/pipecat/processors/frame_processor.py index 69aee0acd..9f27c440b 100644 --- a/src/pipecat/processors/frame_processor.py +++ b/src/pipecat/processors/frame_processor.py @@ -142,6 +142,7 @@ class FrameProcessor(BaseObject): - on_after_process_frame: Called after a frame is processed - on_before_push_frame: Called before a frame is pushed - on_after_push_frame: Called after a frame is pushed + - on_error: Called when an error is raised in the frame processing. """ def __init__( @@ -234,6 +235,7 @@ class FrameProcessor(BaseObject): self._register_event_handler("on_after_process_frame", sync=True) self._register_event_handler("on_before_push_frame", sync=True) self._register_event_handler("on_after_push_frame", sync=True) + self._register_event_handler("on_error", sync=True) @property def id(self) -> int: @@ -630,15 +632,46 @@ class FrameProcessor(BaseObject): elif isinstance(frame, (FrameProcessorResumeFrame, FrameProcessorResumeUrgentFrame)): await self.__resume(frame) - async def push_error(self, error: ErrorFrame): - """Push an error frame upstream. + async def push_error( + self, + error_message: Optional[str] = None, + exception: Optional[Exception] = None, + fatal: bool = False, + ): + """Creates and pushes an ErrorFrame upstream. + + Creates and pushes an ErrorFrame upstream to notify other processors in the + pipeline about an error condition. The error frame will include context about + which processor generated the error. Args: - error: The error frame to push. + error_message: Optional descriptive message explaining the error condition. + exception: Optional exception object that caused the error, if available. + This provides additional context for debugging and error handling. + fatal: Whether this error should be considered fatal to the pipeline. + Fatal errors typically cause the entire pipeline to stop processing. + Defaults to False for non-fatal errors. + + Example: + ```python + # Non-fatal error + await self.push_error("Failed to process audio chunk, skipping") + + # Fatal error with exception context + try: + result = some_critical_operation() + except Exception as e: + await self.push_error("Critical operation failed", exception=e, fatal=True) + ``` """ - if not error.processor: - error.processor = self - await self.push_frame(error, FrameDirection.UPSTREAM) + error_message = error_message or f"{self} exception: {exception}" + logger.error(error_message) + error_frame = ErrorFrame(error=error_message, fatal=fatal, exception=exception) + await self._call_event_handler("on_error", error_frame) + await self.push_frame( + error_frame, + FrameDirection.UPSTREAM, + ) async def push_frame(self, frame: Frame, direction: FrameDirection = FrameDirection.DOWNSTREAM): """Push a frame to the next processor in the pipeline. diff --git a/src/pipecat/services/fish/tts.py b/src/pipecat/services/fish/tts.py index 5fe129998..db4f0f387 100644 --- a/src/pipecat/services/fish/tts.py +++ b/src/pipecat/services/fish/tts.py @@ -228,8 +228,7 @@ class FishAudioTTSService(InterruptibleTTSService): await self._call_event_handler("on_connected") except Exception as e: - logger.error(f"{self} exception: {e}") - await self.push_error(ErrorFrame(error=f"{self} error: {e}")) + await self.push_error(exception=e) self._websocket = None await self._call_event_handler("on_connection_error", f"{e}")