From ff9323dcfd5c642ace4a3fd306565191fa71a519 Mon Sep 17 00:00:00 2001 From: Maxim Vlah Date: Mon, 11 Aug 2025 12:38:00 +0200 Subject: [PATCH 1/4] feat: nullable exception handlers --- reflex/app.py | 15 ++++++++++----- reflex/state.py | 13 +++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index 6d84e6793d6..fdde95a488e 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -422,14 +422,14 @@ class App(MiddlewareMixin, LifespanMixin): _background_tasks: set[asyncio.Task] = dataclasses.field(default_factory=set) # Frontend Error Handler Function - frontend_exception_handler: Callable[[Exception], None] = ( + frontend_exception_handler: Callable[[Exception], None] | None = ( default_frontend_exception_handler ) # Backend Error Handler Function - backend_exception_handler: Callable[ - [Exception], EventSpec | list[EventSpec] | None - ] = default_backend_exception_handler + backend_exception_handler: ( + Callable[[Exception], EventSpec | list[EventSpec] | None] | None + ) = default_backend_exception_handler # Put the toast provider in the app wrap. toaster: Component | None = dataclasses.field(default_factory=toast.provider) @@ -1620,6 +1620,10 @@ def _validate_exception_handlers(self): ], strict=True, ): + if handler_fn is None: + # If the handler is None, skip validation. + continue + if hasattr(handler_fn, "__name__"): _fn_name = handler_fn.__name__ else: @@ -1773,7 +1777,8 @@ async def process( except Exception as ex: telemetry.send_error(ex, context="backend") - app.backend_exception_handler(ex) + if app.backend_exception_handler is not None: + app.backend_exception_handler(ex) raise diff --git a/reflex/state.py b/reflex/state.py index 639fb3dbbef..1a5ed32ef8e 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1880,8 +1880,12 @@ async def _process_event( except Exception as ex: telemetry.send_error(ex, context="backend") + app = prerequisites.get_and_validate_app().app + event_specs = ( - prerequisites.get_and_validate_app().app.backend_exception_handler(ex) + app.backend_exception_handler(ex) + if app.backend_exception_handler + else None ) yield await state._as_state_update( @@ -2433,9 +2437,10 @@ def handle_frontend_exception(self, info: str, component_stack: str) -> None: component_stack: The stack trace of the component where the exception occurred. """ - prerequisites.get_and_validate_app().app.frontend_exception_handler( - Exception(info) - ) + app = prerequisites.get_and_validate_app().app + + if app.frontend_exception_handler is not None: + app.frontend_exception_handler(Exception(info)) class UpdateVarsInternalState(State): From 5e77d17338ea2b88fb2b472558f98c258d71d752 Mon Sep 17 00:00:00 2001 From: Maxim Vlah Date: Mon, 11 Aug 2025 12:42:04 +0200 Subject: [PATCH 2/4] fix: fixed validation of handlers --- reflex/app.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/reflex/app.py b/reflex/app.py index fdde95a488e..82a730cd8a9 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1669,7 +1669,10 @@ def _validate_exception_handlers(self): raise ValueError(msg) # Check if the return type is valid for backend exception handler - if handler_domain == "backend": + if ( + handler_domain == "backend" + and self.backend_exception_handler is not None + ): sig = inspect.signature(self.backend_exception_handler) return_type = ( eval(sig.return_annotation) From 20b467f32682a8b12ab270462512b3397bc0cc03 Mon Sep 17 00:00:00 2001 From: Maxim Vlah Date: Mon, 11 Aug 2025 12:46:04 +0200 Subject: [PATCH 3/4] fix: pyright fixes --- reflex/state.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/reflex/state.py b/reflex/state.py index 1a5ed32ef8e..b4305eb64c6 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1742,8 +1742,11 @@ async def _as_state_update( except Exception as ex: state._clean() + app = prerequisites.get_and_validate_app().app event_specs = ( - prerequisites.get_and_validate_app().app.backend_exception_handler(ex) + app.backend_exception_handler(ex) + if app.backend_exception_handler + else None ) if event_specs is None: From 7ceac105b7432c425afee0776aaa4435cd367bff Mon Sep 17 00:00:00 2001 From: Maxim Vlah Date: Wed, 13 Aug 2025 12:41:55 +0200 Subject: [PATCH 4/4] fix: use is not None --- reflex/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index b4305eb64c6..388620e7a68 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1745,7 +1745,7 @@ async def _as_state_update( app = prerequisites.get_and_validate_app().app event_specs = ( app.backend_exception_handler(ex) - if app.backend_exception_handler + if app.backend_exception_handler is not None else None ) @@ -1887,7 +1887,7 @@ async def _process_event( event_specs = ( app.backend_exception_handler(ex) - if app.backend_exception_handler + if app.backend_exception_handler is not None else None )