Repository navigation
Description
🔴 Required Information
Describe the Bug:
In task mode, RemoteA2aAgent._run_async_impl yields the finish_task and agent state events from its finally block. Most failure paths (authentication or initialization failure, no parts to send, a request interceptor returning an event, an unfinished stream, a request error) set should_release_task_control before they yield the error event. If the generator is closed while it is paused at that error event, the finally block yields again and Python raises RuntimeError: async generator ignored GeneratorExit.
This happens when the caller stops reading Runner.run_async() at that event, with break or by cancelling the task. The Runner then cancels the root node, and the cancellation closes the agent's generator. The RuntimeError replaces the cancellation:
NodeRunnerhandles it as a node failure. It logsNode execution failed with exceptionwith the traceback below, andon_agent_error_callbackplugins receive theRuntimeError.NodeRunnerthen enqueues an error event for that failure. Nothing reads the event queue anymore, so the remote agent's node task waits forever. ClosingRunner.run_async()never finishes, and the caller'sbreakorcancel()hangs.
With abort_signal passed to run_async(), the run still closes, but the log and the plugin callback happen the same way.
Steps to Reproduce:
- Run the code below. Nothing listens on
127.0.0.1:9, so the remote agent fails to initialize.
Expected Behavior:
The run closes after break, and no agent error is reported.
stopping at: Failed to initialize remote A2A agent: ...
closed
Observed Behavior:
closed is never printed and the script does not exit. Before it hangs, this is logged:
Node execution failed with exception
Traceback (most recent call last):
File ".../google/adk/agents/base_agent.py", line 448, in _run
yield event
GeneratorExit
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ".../google/adk/workflow/_node_runner.py", line 170, in run
await self._execute_node(ctx, node_input)
...
File ".../google/adk/agents/base_agent.py", line 446, in _run
async with Aclosing(impl_fn(ctx)) as agen:
...
RuntimeError: async generator ignored GeneratorExit
The plugin also prints on_agent_error_callback: RuntimeError('async generator ignored GeneratorExit').
Environment Details:
- ADK Library Version (pip show google-adk): 2.13.0 (also on
mainat 9a5117b) - Desktop OS: macOS
- Python Version (python -V): 3.14.7
Model Information:
- Are you using LiteLLM: No
- Which model is being used: N/A (the repro uses a stub model)
🟡 Optional Information
Additional Context:
Calling _run_async_impl directly shows the cause: after the first (error) event, aclose() raises the RuntimeError in task mode and returns normally when mode is not set.
Only the paths that set should_release_task_control before yielding are affected. A close while the response stream is being read, or after finish_task is received, is fine.
Minimal Reproduction Code:
import asyncio
from google.adk.agents import LlmAgent
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.apps import App
from google.adk.models import BaseLlm
from google.adk.models import LlmResponse
from google.adk.plugins import BasePlugin
from google.adk.runners import InMemoryRunner
from google.adk.utils.context_utils import Aclosing
from google.genai import types
class CallRemote(BaseLlm):
async def generate_content_async(self, llm_request, stream=False):
yield LlmResponse(
content=types.Content(
role="model",
parts=[types.Part.from_function_call(name="remote", args={})],
)
)
class PrintAgentErrors(BasePlugin):
async def on_agent_error_callback(self, *, agent, callback_context, error):
print("on_agent_error_callback:", repr(error))
async def main():
remote = RemoteA2aAgent(
name="remote",
description="Remote agent",
agent_card="http://127.0.0.1:9/.well-known/agent-card.json",
mode="task",
)
root = LlmAgent(
name="root", model=CallRemote(model="call-remote"), sub_agents=[remote]
)
runner = InMemoryRunner(
app=App(
name="app",
root_agent=root,
plugins=[PrintAgentErrors(name="print_agent_errors")],
)
)
session = await runner.session_service.create_session(
app_name="app", user_id="user"
)
async with Aclosing(
runner.run_async(
user_id="user",
session_id=session.id,
new_message=types.Content(
role="user", parts=[types.Part(text="start")]
),
)
) as events:
async for event in events:
if event.author == "remote" and event.error_message:
print("stopping at:", event.error_message)
break
print("closed")
asyncio.run(main())How often has this issue occurred?:
- Always (100%)
Activity
llalitkumarrr commentedon Nov 5, 2026
Hello @hyeonsang010716,
Thank you for raising this issue and for your contribution. Your PR is currently under review and will be merged once the changes are approved, we appreciate your patience in the meantime.