Repository navigation
message_as_output=True unconditionally set, destroying structured event.output for single_turn agents with output_schema #6089
Description
🔴 Required Information
Describe the Bug
When a single_turn LlmAgent is configured with an output_schema, the validated structured output is lost before it reaches downstream consumers.
The issue occurs because process_llm_agent_output() in _llm_agent_wrapper.py unconditionally sets:
event.node_info.message_as_output = Trueeven when the agent is producing structured output through output_schema.
Later, _consume_event_queue() in runners.py interprets message_as_output=True as a signal that the message content itself represents the node output and clears event.output to avoid duplication.
As a result, the structured output stored in event.output is overwritten with None.
The implementation also appears to contradict the documented intent in _consume_event_queue(), whose comments explicitly describe message_as_output as applying only to the "no output_schema" case.
Steps to Reproduce
-
Create an
LlmAgentwith:mode="single_turn"(or use it as a workflow node)- an
output_schemabased on a Pydantic model
-
Execute the agent through a runner instance:
runner = InMemoryRunner(agent=agent)
events = await runner.run_async(...)or:
runner = Runner(...)
events = await runner.run_async(...)-
Inspect the emitted events.
-
Observe that:
event.outputis always None, even when the model successfully produces valid structured output.
Expected Behavior
When an output_schema is configured and validation succeeds:
event.outputshould contain the validated structured result.
Downstream consumers should be able to access the structured output through the event stream.
Observed Behavior
For single_turn agents using output_schema:
event.outputis always None.
The structured output is generated correctly but is later removed by _consume_event_queue() because message_as_output was set unconditionally.
Environment Details
- ADK Library Version: Latest
mainbranch - Desktop OS: N/A (identified via static code analysis)
- Python Version: N/A
Model Information
- Using LiteLLM: No
- Model: Any model used with
output_schema
🟡 Optional Information
Additional Context
The issue involves two locations.
1. src/google/adk/workflow/_llm_agent_wrapper.py
process_llm_agent_output() sets:
event.output = output
event.node_info.message_as_output = TrueThe flag is enabled regardless of whether the output is plain text or a validated structured result.
2. src/google/adk/runners.py
_consume_event_queue() contains logic similar to:
if not event.partial:
if event.node_info.message_as_output and event.content is not None:
event = event.model_copy()
event.output = NoneThis removes the structured output before the event is returned.
Documentation / Implementation Mismatch
The comment in _consume_event_queue() (approximately lines 788–794) states:
When an LlmAgent node uses message_as_output (no output_schema), the wrapper sets both event.content and event.output to the same text. event.output is cleared here to avoid rendering the same value twice.
This comment explicitly limits the behavior to the no output_schema case.
However, the current implementation sets message_as_output = True regardless of whether an output_schema exists.
Suggested Fix
Only mark the message as the output when no structured output schema is configured:
event.output = output
if not agent.output_schema:
event.node_info.message_as_output = TrueMinimal Reproduction
from pydantic import BaseModel
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner
class WeatherOutput(BaseModel):
temperature: float
condition: str
agent = LlmAgent(
name="weather_agent",
model="gemini-2.0-flash",
output_schema=WeatherOutput,
instruction="Return weather data as structured output.",
)
runner = InMemoryRunner(agent=agent)
events = await runner.run_async(
user_id="test",
session_id="test",
new_message=types.Content(
parts=[types.Part(text="What is the weather in Tokyo?")]
),
)
for event in events:
print(event.output) # Always NoneFrequency
- Always reproducible (100%)
Activity
sanketpatil06 commentedon Jun 15, 2026
Hi @wi5nuu, thanks for reporting this and providing the details. We were able to reproduce this issue on our end.
We see that PR (#6100) is already open to address this and is currently under review. Could you please confirm if this resolves the issue for you? Thanks.
In the meantime, you can use the following workaround to parse the raw JSON from
event.content:wi5nuu commentedon Jun 15, 2026
Confirmed — the fix in PR #6100 looks correct. The conditional if not agent.output_schema directly addresses the root cause. Thank you for the quick turnaround.
fix: preserve single-turn structured output