You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ADK 2.0 ignores before_run callback for Workflow #6013
ADK 2.0 ignores before_run callback returning a value for workflows. In this case the execution should stop and no further llm calls should be executed.
swallows returned value and never checks if execution should continue
Steps to Reproduce:
Use Workflow as root_agent
Implement plugin and override before_run_callback
Expected Behavior:
Execution should stop if before_run_callback returns a value as described here:
"Returning a value to halt execution of the runner and ends the runner with that event"
I will begin by reading the instructions for the adk-issue-analyze skill to understand the strict read-only analysis process.I will fetch the details of GitHub issue #6013.I will search for the path of runner.py using find_by_name.I will search for the string run_before_run_callback to locate where this callback is invoked.I will view src/google/adk/runners.py starting around line 500 to check how run_before_run_callback is called.I will view src/google/adk/runners.py around line 1350 to see the second usage of run_before_run_callback.I will view src/google/adk/runners.py from line 440 to 500 to identify the surrounding class and method.I will search for the class definitions in runners.py to see which class contains _run_node_async.I will search for _run_node_async calls in runners.py.I will view lines 580 to 650 of src/google/adk/runners.py.I will view src/google/adk/runners.py from line 640 to 700 to check for any usage of run_before_run_callback in _run_node_live.I will run a gh command to search for any pull requests associated with issue #6013.I will search for test files related to plugins or runners to see how they are tested.I will search for callback or plugin test instances in tests/unittests/test_runners.py.I will view tests/unittests/test_runners.py from line 145 to 180 to inspect the test plugin setup.I will view lines 940 to 960 in tests/unittests/test_runners.py.I will view the tests/unittests/runners/test_runner_node.py file to see how node or workflow runners are tested.I will view src/google/adk/plugins/plugin_manager.py around line 145 to see how run_before_run_callback handles returning values.I will run the runner node unit tests to confirm the test suite is functioning correctly.# GitHub Issue #6013 Analysis: ADK 2.0 ignores before_run callback for Workflow
Executive Summary
What is broken? When executing a workflow (or any other BaseNode / agent node) via Runner(node=...), ADK 2.0 executes _run_node_async where it discards the return value of before_run_callback. Unlike the standard LLM sequential execution path in _exec_with_plugin, early exit returned values of type types.Content are swallowed and never checked, letting node/workflow execution progress unchecked.
Is there a linked PR that fixes this issue? None
Recommendation: Should Fix (High Priority) - Update _run_node_async to capture the callback return value and gracefully early-exit if a types.Content instance is returned, mirroring the behavior of _exec_with_plugin.
Detailed Analysis
1. Root Cause Analysis ("What is broken?")
The Bug:
In runners.py, agent workflows are executed through _run_node_async because Workflow is a subclass of BaseNode. At line 532, the before-run callbacks are executed:
# Run before_run callbacksawaitic.plugin_manager.run_before_run_callback(invocation_context=ic)
The returned value of type Optional[types.Content] is ignored/discarded. Consequently, if a plugin returns a non-None value to stop execution and end the runner, the runner ignores it and schedules the root node/workflow anyway.
In comparison, the sequential execution wrapper _exec_with_plugin in runners.py:L1373-1393 correctly evaluates the callback return value:
Reference working code structure: runners.py:L1373-L1393
2. Existing Pull Requests ("Is there a linked PR that fixes this issue?")
Linked PR: None
Analysis: Command gh pr list --search "6013" returned no related PRs.
3. Recommendation
Recommendation: Should Fix (High Priority)
Rationale:
Impact: Swallowing before-run callback outputs during workflow runs breaks the documented contract of interrupting runners cleanly. Under normal conditions, interrupting workflows early is highly critical to preventing unnecessary LLM charges and downstream orchestration side-effects.
Implementation Complexity: Low. The fix is localized to _run_node_async and matches the pattern employed by _exec_with_plugin.
Located & Analyzed MALFUNCTIONING Code: Traced workflow execution to the _run_node_async routing in runners.py and inspected the missing check on run_before_run_callback.
To help us investigate this issue, could you please share your reproduction code, the steps to reproduce the behavior and any additional observations you have?
Additionally, you can refer to this page in the ADK documentation to verify your implementation.
Hello @llalitkumarrr
I cannot share the reproduction code as it is our internal protected code.
But the root of the problem is simple. In the new 2.0 implementation, the plugins are not working properly because of line
This issue has been automatically marked as stale because it has not had recent activity for 7 days after a maintainer requested clarification. It will be closed if no further activity occurs within 7 days.
Activity
adk-bot commentedon Jun 8, 2026
I will begin by reading the instructions for the adk-issue-analyze skill to understand the strict read-only analysis process.I will fetch the details of GitHub issue #6013.I will search for the path of
runner.pyusingfind_by_name.I will search for the stringrun_before_run_callbackto locate where this callback is invoked.I will viewsrc/google/adk/runners.pystarting around line 500 to check howrun_before_run_callbackis called.I will viewsrc/google/adk/runners.pyaround line 1350 to see the second usage ofrun_before_run_callback.I will viewsrc/google/adk/runners.pyfrom line 440 to 500 to identify the surrounding class and method.I will search for the class definitions inrunners.pyto see which class contains_run_node_async.I will search for_run_node_asynccalls inrunners.py.I will view lines 580 to 650 ofsrc/google/adk/runners.py.I will viewsrc/google/adk/runners.pyfrom line 640 to 700 to check for any usage ofrun_before_run_callbackin_run_node_live.I will run aghcommand to search for any pull requests associated with issue #6013.I will search for test files related to plugins or runners to see how they are tested.I will search for callback or plugin test instances intests/unittests/test_runners.py.I will viewtests/unittests/test_runners.pyfrom line 145 to 180 to inspect the test plugin setup.I will view lines 940 to 960 intests/unittests/test_runners.py.I will view thetests/unittests/runners/test_runner_node.pyfile to see how node or workflow runners are tested.I will viewsrc/google/adk/plugins/plugin_manager.pyaround line 145 to see howrun_before_run_callbackhandles returning values.I will run the runner node unit tests to confirm the test suite is functioning correctly.# GitHub Issue #6013 Analysis: ADK 2.0 ignores before_run callback for WorkflowExecutive Summary
BaseNode/ agent node) viaRunner(node=...), ADK 2.0 executes_run_node_asyncwhere it discards the return value ofbefore_run_callback. Unlike the standard LLM sequential execution path in_exec_with_plugin, early exit returned values of typetypes.Contentare swallowed and never checked, letting node/workflow execution progress unchecked._run_node_asyncto capture the callback return value and gracefully early-exit if atypes.Contentinstance is returned, mirroring the behavior of_exec_with_plugin.Detailed Analysis
1. Root Cause Analysis ("What is broken?")
The Bug:
In runners.py, agent workflows are executed through
_run_node_asyncbecauseWorkflowis a subclass ofBaseNode. At line 532, the before-run callbacks are executed:The returned value of type
Optional[types.Content]is ignored/discarded. Consequently, if a plugin returns a non-Nonevalue to stop execution and end the runner, the runner ignores it and schedules the root node/workflow anyway.In comparison, the sequential execution wrapper
_exec_with_pluginin runners.py:L1373-1393 correctly evaluates the callback return value:Code References:
2. Existing Pull Requests ("Is there a linked PR that fixes this issue?")
gh pr list --search "6013"returned no related PRs.3. Recommendation
_run_node_asyncand matches the pattern employed by_exec_with_plugin.Replace runners.py:L531-L532 with:
Summary of Completed Steps
_run_node_asyncrouting in runners.py and inspected the missing check onrun_before_run_callback.llalitkumarrr commentedon Jun 10, 2026
Hello @mfojtak ,
To help us investigate this issue, could you please share your reproduction code, the steps to reproduce the behavior and any additional observations you have?
Additionally, you can refer to this page in the ADK documentation to verify your implementation.
mfojtak commentedon Jun 10, 2026
Hello @llalitkumarrr
I cannot share the reproduction code as it is our internal protected code.
But the root of the problem is simple. In the new 2.0 implementation, the plugins are not working properly because of line
which ignores return value of the run_before_run_callback function and violates the predefined behavior of any plugin.
The correct behavior is implemented in the old pre-2.0 code:
where the return value is checked for early exit.
llalitkumarrr commentedon Jun 17, 2026
Hello @mfojtak ,
Could please have a look at #6032 check if this fix your issue?
adk-bot commentedon Jun 26, 2026
This issue has been automatically marked as stale because it has not had recent activity for 7 days after a maintainer requested clarification. It will be closed if no further activity occurs within 7 days.
adk-bot commentedon Jul 4, 2026
This has been automatically closed because it has been marked as stale for over 7 days.
fix: honor before_run_callback early-exit for Workflow runs