🔴 Required Information
Describe the Bug:
AgentTool(propagate_grounding_metadata=True)—which GoogleSearchAgentTool
enables—stores a raw google.genai.types.GroundingMetadata instance in session
state under temp:_adk_grounding_metadata. That value reaches
EventActions.state_delta, which is typed as dict[str, Any], so event
serialization relies on Pydantic's duck-typed serialization of the value.
google-genai 2.18.0 and newer configure their generated models with
defer_build=True. A GroundingMetadata produced by nested validation (for
example, as part of Candidate validation, as happens for model responses)
leaves GroundingMetadata.__pydantic_serializer__ as a MockValSer.
Serializing the event then raises:
pydantic_core._pydantic_core.PydanticSerializationError: Error calling function `_serialize_state_delta`: TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'
The _make_json_serializable fallback introduced by #4748 does not recover
from this case. pydantic_core.to_jsonable_python(value, serialize_unknown=True) raises the same TypeError before
serialize_unknown can apply, so the exception escapes
_serialize_state_delta.
This surfaces in merge_parallel_function_response_events in
google/adk/flows/llm_flows/functions.py, which calls
event.actions.model_dump(exclude_none=True, by_alias=True). When a search call
runs in parallel with another function call, the merge raises and aborts the
invocation.
This is related to #4748 and prior grounding-metadata persistence reports such
as #5840, but it is a distinct failure mode: the value is a valid Pydantic
model whose deferred serializer has not been built.
Steps to Reproduce:
-
Install the affected versions:
python -m pip install "google-adk==2.7.1" "google-genai==2.19.0" "pydantic==2.13.4"
-
Run the snippet under Minimal Reproduction Code below. It requires no
model call or API key.
-
Observe the PydanticSerializationError above.
Expected Behavior:
Serializing an event whose state_delta contains grounding metadata propagated
by ADK succeeds, and parallel function-response merging preserves both tool
results. ADK-created state should not depend on whether a deferred class
serializer happened to be built earlier in the process.
Observed Behavior:
EventActions.model_dump(...) raises from
merge_parallel_function_response_events, and the invocation terminates
without a final response.
Environment Details:
- ADK Library Version: 2.7.1 (also reproduced on 2.7.0)
- Desktop OS: macOS 26.6 (also reproduced on Linux)
- Python Version: 3.14.6 (also reproduced on 3.12.6)
google-genai: 2.19.0 (also reproduced on 2.18.1)
pydantic: 2.13.4 / pydantic-core: 2.46.4
Model Information:
- Are you using LiteLLM: No
- Which model is being used: N/A—the minimal reproduction performs no model
call and requires no API key.
🟡 Optional Information
Regression:
This is a google-genai 2.18.0 regression:
google-genai==2.17.0: nested GroundingMetadata has a built
SchemaSerializer; the merge succeeds.
google-genai==2.18.0: the shared model config includes defer_build=True;
nested GroundingMetadata retains a MockValSer; the merge fails.
The failure also reproduces with google-adk==2.6.0 plus
google-genai==2.18.1, so it is not specific to ADK 2.7.x. ADK is affected
because it propagates the raw deferred model through state_delta and then
serializes that state while merging parallel tool responses.
Logs:
Failed to serialize `state_delta`; some values are not JSON-serializable and
will be replaced with a string representation in the persisted event.
Traceback (most recent call last):
File "google/adk/events/event_actions.py", line 106, in _serialize_state_delta
return cast(dict[str, Any], handler(value))
TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'
During fallback handling, `to_jsonable_python(...)` raises the same TypeError.
The resulting PydanticSerializationError escapes the parallel-response merge.
Additional Context:
Two details make this easy to miss in tests:
- Constructing
types.GroundingMetadata(...) directly builds the serializer as
a side effect. Nested validation via types.Candidate.model_validate(...),
which mirrors the response-validation path, leaves the MockValSer.
- Once anything else in the process builds this class serializer, the failure
disappears for subsequent calls.
Possible fixes, in rough order of narrowness:
- Build
types.GroundingMetadata before ADK propagates or serializes it, for
example with types.GroundingMetadata.model_rebuild(force=True). Removing
defer_build for this model in google-genai would also resolve the root
behavior.
- Store grounding metadata in
state_delta in serialized form, then
revalidate it where base_llm_flow attaches it to the response.
- Make
_make_json_serializable resilient per value so the fallback cannot
itself abort event serialization. This is defense in depth and would
degrade the metadata rather than preserve it.
Happy to send a PR for the preferred direction.
Minimal Reproduction Code:
from google.adk.events import Event, EventActions
from google.adk.flows.llm_flows.functions import (
merge_parallel_function_response_events,
)
from google.genai import types
candidate = types.Candidate.model_validate(
{"groundingMetadata": {"webSearchQueries": ["some query"]}}
)
print(type(types.GroundingMetadata.__pydantic_serializer__).__name__)
# MockValSer
def response_event(name: str, state_delta: dict) -> Event:
return Event(
invocation_id="inv",
author="my_agent",
content=types.Content(
role="user",
parts=[
types.Part.from_function_response(
name=name,
response={"ok": True},
)
],
),
actions=EventActions(state_delta=state_delta),
)
events = [
response_event(
"search_agent",
{"temp:_adk_grounding_metadata": candidate.grounding_metadata},
),
response_event("other_tool", {"temp:other": 1}),
]
merge_parallel_function_response_events(events)
# PydanticSerializationError
The fallback also fails directly:
from pydantic_core import to_jsonable_python
to_jsonable_python(
{"k": candidate.grounding_metadata},
serialize_unknown=True,
)
# TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'
How often has this issue occurred?:
- Always (100%) when a deferred
GroundingMetadata is present in one of two
or more function-response events being merged.
🔴 Required Information
Describe the Bug:
AgentTool(propagate_grounding_metadata=True)—whichGoogleSearchAgentToolenables—stores a raw
google.genai.types.GroundingMetadatainstance in sessionstate under
temp:_adk_grounding_metadata. That value reachesEventActions.state_delta, which is typed asdict[str, Any], so eventserialization relies on Pydantic's duck-typed serialization of the value.
google-genai2.18.0 and newer configure their generated models withdefer_build=True. AGroundingMetadataproduced by nested validation (forexample, as part of
Candidatevalidation, as happens for model responses)leaves
GroundingMetadata.__pydantic_serializer__as aMockValSer.Serializing the event then raises:
The
_make_json_serializablefallback introduced by #4748 does not recoverfrom this case.
pydantic_core.to_jsonable_python(value, serialize_unknown=True)raises the sameTypeErrorbeforeserialize_unknowncan apply, so the exception escapes_serialize_state_delta.This surfaces in
merge_parallel_function_response_eventsingoogle/adk/flows/llm_flows/functions.py, which callsevent.actions.model_dump(exclude_none=True, by_alias=True). When a search callruns in parallel with another function call, the merge raises and aborts the
invocation.
This is related to #4748 and prior grounding-metadata persistence reports such
as #5840, but it is a distinct failure mode: the value is a valid Pydantic
model whose deferred serializer has not been built.
Steps to Reproduce:
Install the affected versions:
Run the snippet under Minimal Reproduction Code below. It requires no
model call or API key.
Observe the
PydanticSerializationErrorabove.Expected Behavior:
Serializing an event whose
state_deltacontains grounding metadata propagatedby ADK succeeds, and parallel function-response merging preserves both tool
results. ADK-created state should not depend on whether a deferred class
serializer happened to be built earlier in the process.
Observed Behavior:
EventActions.model_dump(...)raises frommerge_parallel_function_response_events, and the invocation terminateswithout a final response.
Environment Details:
google-genai: 2.19.0 (also reproduced on 2.18.1)pydantic: 2.13.4 /pydantic-core: 2.46.4Model Information:
call and requires no API key.
🟡 Optional Information
Regression:
This is a
google-genai2.18.0 regression:google-genai==2.17.0: nestedGroundingMetadatahas a builtSchemaSerializer; the merge succeeds.google-genai==2.18.0: the shared model config includesdefer_build=True;nested
GroundingMetadataretains aMockValSer; the merge fails.The failure also reproduces with
google-adk==2.6.0plusgoogle-genai==2.18.1, so it is not specific to ADK 2.7.x. ADK is affectedbecause it propagates the raw deferred model through
state_deltaand thenserializes that state while merging parallel tool responses.
Logs:
Additional Context:
Two details make this easy to miss in tests:
types.GroundingMetadata(...)directly builds the serializer asa side effect. Nested validation via
types.Candidate.model_validate(...),which mirrors the response-validation path, leaves the
MockValSer.disappears for subsequent calls.
Possible fixes, in rough order of narrowness:
types.GroundingMetadatabefore ADK propagates or serializes it, forexample with
types.GroundingMetadata.model_rebuild(force=True). Removingdefer_buildfor this model ingoogle-genaiwould also resolve the rootbehavior.
state_deltain serialized form, thenrevalidate it where
base_llm_flowattaches it to the response._make_json_serializableresilient per value so the fallback cannotitself abort event serialization. This is defense in depth and would
degrade the metadata rather than preserve it.
Happy to send a PR for the preferred direction.
Minimal Reproduction Code:
The fallback also fails directly:
How often has this issue occurred?:
GroundingMetadatais present in one of twoor more function-response events being merged.