From 92fea1a4fe3bf67566661bf79dbbc18426e8923f Mon Sep 17 00:00:00 2001 From: Yanhu007 Date: Sun, 12 Apr 2026 19:37:06 +0800 Subject: [PATCH] fix: propagate OutputCheckError to caller instead of swallowing it OutputCheckError raised in output_validation_post_hook is caught internally and returned as a normal RunResponse with error status. This means try/except OutputCheckError never reaches the except block, contradicting the documented usage pattern. Re-raise InputCheckError/OutputCheckError after cleanup/logging in all four non-streaming run methods: - _run (sync) - _arun (async) - _continue_run (sync continuation) - _acontinue_run (async continuation) Streaming methods (_run_stream, _arun_stream, etc.) still return the error response since exceptions can't propagate mid-stream. Fixes #7414 --- libs/agno/agno/agent/_run.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libs/agno/agno/agent/_run.py b/libs/agno/agno/agent/_run.py index a746a47378..1a89b30be2 100644 --- a/libs/agno/agno/agent/_run.py +++ b/libs/agno/agno/agent/_run.py @@ -639,7 +639,8 @@ def _run( return run_response except (InputCheckError, OutputCheckError) as e: - # Handle exceptions during streaming + # Handle validation exceptions — propagate to caller so + # try/except OutputCheckError works as documented. run_response.status = RunStatus.error # If the content is None, set it to the error message if run_response.content is None: @@ -656,7 +657,7 @@ def _run( user_id=user_id, ) - return run_response + raise except KeyboardInterrupt: run_response = cast(RunOutput, run_response) run_response.status = RunStatus.cancelled @@ -1734,7 +1735,8 @@ async def _arun( return run_response except (InputCheckError, OutputCheckError) as e: - # Handle exceptions during streaming + # Handle validation exceptions — propagate to caller so + # try/except OutputCheckError works as documented. run_response.status = RunStatus.error # If the content is None, set it to the error message if run_response.content is None: @@ -1751,7 +1753,7 @@ async def _arun( user_id=user_id, ) - return run_response + raise except KeyboardInterrupt: run_response = cast(RunOutput, run_response) @@ -3049,7 +3051,8 @@ def _continue_run( return run_response except (InputCheckError, OutputCheckError) as e: run_response = cast(RunOutput, run_response) - # Handle exceptions during streaming + # Handle validation exceptions — propagate to caller so + # try/except OutputCheckError works as documented. run_response.status = RunStatus.error # If the content is None, set it to the error message if run_response.content is None: @@ -3061,7 +3064,7 @@ def _continue_run( agent, run_response=run_response, session=session, run_context=run_context, user_id=user_id ) - return run_response + raise except KeyboardInterrupt: run_response = cast(RunOutput, run_response) run_response.status = RunStatus.cancelled @@ -3842,7 +3845,8 @@ async def _acontinue_run( return run_response except (InputCheckError, OutputCheckError) as e: run_response = cast(RunOutput, run_response) - # Handle exceptions during streaming + # Handle validation exceptions — propagate to caller so + # try/except OutputCheckError works as documented. run_response.status = RunStatus.error # If the content is None, set it to the error message if run_response.content is None: @@ -3859,7 +3863,7 @@ async def _acontinue_run( user_id=user_id, ) - return run_response + raise except KeyboardInterrupt: run_response = cast(RunOutput, run_response)