Overview
Every frame processor in Pipecat — including all services, transports, and custom processors — inherits from FrameProcessor and exposes a set of events for error handling and frame monitoring. These events are synchronous, meaning handlers run inline and must execute quickly to avoid blocking the pipeline.
Events Summary
| Event | Description |
|---|
on_error | An error occurred in this processor |
on_before_process_frame | A frame is about to be processed |
on_after_process_frame | A frame has just been processed |
on_before_push_frame | A frame is about to be pushed to the next processor |
on_after_push_frame | A frame has just been pushed to the next processor |
Error Handling
on_error
Fired when an error occurs in this processor. This is called before the ErrorFrame is pushed upstream through the pipeline, giving you an opportunity to handle errors at the processor level.
@tts.event_handler("on_error")
async def on_tts_error(processor, error):
print(f"Error in {processor}: {error.error}")
if error.exception:
print(f"Exception: {error.exception}")
if error.fatal:
print("This is a fatal error — pipeline will be cancelled")
Parameters:
| Parameter | Type | Description |
|---|
processor | FrameProcessor | The processor where the error occurred |
error | ErrorFrame | The error frame containing error details |
The ErrorFrame provides:
error (str): The error message
exception (Optional[Exception]): The underlying exception, if any
fatal (bool): Whether this is a fatal error that will cancel the pipeline
processor (Optional[FrameProcessor]): The processor that originated the error
Since on_error is synchronous, the handler runs before the error frame propagates upstream.
Keep your handler fast — use it for logging or setting flags, not for I/O operations.
Example: Error handling across multiple processors
async def handle_service_error(processor, error):
logger.error(f"Service error in {processor.name}: {error.error}")
# Notify monitoring system, set a flag, etc.
# Register the same handler on multiple services
stt.add_event_handler("on_error", handle_service_error)
tts.add_event_handler("on_error", handle_service_error)
llm.add_event_handler("on_error", handle_service_error)
Frame Processing Hooks
These events let you observe frames as they flow through a processor. They’re useful for debugging, logging, or lightweight monitoring.
on_before_process_frame
Fired immediately before a frame is processed by this processor’s process_frame() method.
@stt.event_handler("on_before_process_frame")
async def on_before_process(processor, frame):
print(f"{processor} is about to process: {frame}")
Parameters:
| Parameter | Type | Description |
|---|
processor | FrameProcessor | The processor about to process the frame |
frame | Frame | The frame about to be processed |
on_after_process_frame
Fired immediately after a frame has been processed by this processor’s process_frame() method.
@stt.event_handler("on_after_process_frame")
async def on_after_process(processor, frame):
print(f"{processor} finished processing: {frame}")
Parameters:
| Parameter | Type | Description |
|---|
processor | FrameProcessor | The processor that processed the frame |
frame | Frame | The frame that was processed |
on_before_push_frame
Fired immediately before a frame is pushed to the next processor in the pipeline.
@llm.event_handler("on_before_push_frame")
async def on_before_push(processor, frame):
print(f"{processor} is about to push: {frame}")
Parameters:
| Parameter | Type | Description |
|---|
processor | FrameProcessor | The processor pushing the frame |
frame | Frame | The frame about to be pushed |
on_after_push_frame
Fired immediately after a frame has been pushed to the next processor in the pipeline.
@llm.event_handler("on_after_push_frame")
async def on_after_push(processor, frame):
print(f"{processor} pushed: {frame}")
Parameters:
| Parameter | Type | Description |
|---|
processor | FrameProcessor | The processor that pushed the frame |
frame | Frame | The frame that was pushed |
All frame processing events are synchronous — handlers block the pipeline until they complete. Avoid any I/O, await calls to external services, or other slow operations in these handlers. Use them only for fast operations like logging, counting, or setting flags.