Repository navigation
FirestoreSessionService crashes on GroundingMetadata from GoogleSearchTool - cannot serialize to Firestore #5840
Description
🔴 Required Information
Describe the Bug:
When using GoogleSearchTool with FirestoreSessionService, the session service fails to persist the model's response event because it contains a GroundingMetadata protobuf object that cannot be converted to a Firestore value. This causes the agent response to never be delivered to the client — the SSE stream emits an error instead of the text response.
Steps to Reproduce:
- Configure an agent with
GoogleSearchTooland Firestore session service:
from google.adk.agents import LlmAgent
from google.adk.cli.fast_api import get_fast_api_app
from google.adk.tools.google_search_tool import GoogleSearchTool
root_agent = LlmAgent(
model="gemini-2.5-flash",
name="my_agent",
instruction="You are a helpful assistant.",
tools=[GoogleSearchTool()],
)
app = get_fast_api_app(
agents_dir=".",
session_service_uri="firestore://my-project",
)- Send a query that triggers Google Search (e.g., "Compare MacBook Air and MacBook Pro")
- The model delegates to
google_search_agent, which returns results with grounding metadata - The session service attempts to persist the event to Firestore and fails with:
('Cannot convert to a Firestore Value', GroundingMetadata(...), 'Invalid type', <class 'google.genai.types.GroundingMetadata'>)
Expected Behavior:
The FirestoreSessionService should serialize all objects in the model response (including GroundingMetadata) to Firestore-compatible types before writing. The agent's text response should be delivered to the client via SSE.
Observed Behavior:
The SSE stream emits an error event and the final text response is never delivered:
{"error": "('Cannot convert to a Firestore Value', GroundingMetadata(\n grounding_chunks=[...],\n grounding_supports=[...],\n search_entry_point=SearchEntryPoint(...),\n web_search_queries=[...]\n), 'Invalid type', <class 'google.genai.types.GroundingMetadata'>)"}Environment Details:
- ADK Library Version: google-adk 2.1.0
- Desktop OS: Linux (Cloud Run container)
- Python Version: 3.12
Model Information:
- Are you using LiteLLM: No
- Which model is being used: gemini-2.5-flash (Vertex AI)
🟡 Optional Information
Regression:
Unknown — this is the first time the google_search_agent sub-agent returned results with GroundingMetadata for our queries. It may depend on whether the model decides to ground its response.
Logs:
data: {"error": "('Cannot convert to a Firestore Value', GroundingMetadata(\n grounding_chunks=[\n GroundingChunk(\n web=GroundingChunkWeb(\n domain='forbrukertest.no',\n title='forbrukertest.no',\n uri='https://vertexaisearch.cloud.google.com/grounding-api-redirect/...'\n )\n ),\n ...\n ],\n grounding_supports=[...],\n retrieval_metadata=RetrievalMetadata(),\n search_entry_point=SearchEntryPoint(rendered_content=\"...\"),\n web_search_queries=['MacBook Air vs MacBook Pro sammenligning', ...]\n), 'Invalid type', <class 'google.genai.types.GroundingMetadata'>)"}
Additional Context:
The issue occurs specifically when GoogleSearchTool is used as a sub-agent tool (the model emits a functionCall to google_search_agent). The GroundingMetadata object is attached to the sub-agent's response and then ADK tries to write it to Firestore as part of the session event. The object is a complex protobuf/Pydantic type that Firestore's Python client cannot natively serialize.
Using InMemorySessionService does not trigger this bug since no serialization is needed.
Minimal Reproduction Code:
from google.adk.agents import LlmAgent
from google.adk.cli.fast_api import get_fast_api_app
from google.adk.tools.google_search_tool import GoogleSearchTool
root_agent = LlmAgent(
model="gemini-2.5-flash",
name="test_agent",
instruction="Use Google Search to answer questions.",
tools=[GoogleSearchTool()],
)
app = get_fast_api_app(
agents_dir=".",
session_service_uri="firestore://my-project",
)
# Send: "Compare MacBook Air and MacBook Pro" → triggers grounding → crashHow often has this issue occurred?:
- Always (100%) — every time
google_search_agentreturns grounded results
Activity
surajksharma07 commentedon May 26, 2026
@tinnitussen the session_only_state filter in firestore_session_service.py (lines 549–554) excludes app: and user: prefixed keys but misses temp:, so temp:_adk_grounding_metadata (a raw GroundingMetadata object set by agent_tool.py:294) passes through directly to the Firestore client which can't serialize it.
The approach in PR #5841 looks right — adding and not k.startswith(State.TEMP_PREFIX) to that filter should prevent any temp: scoped state from reaching Firestore, not just this particular key.
Could you confirm the fix holds up end-to-end on your setup — specifically that grounded search responses now persist correctly and the SSE stream delivers the text response without errors?
If it checks out across your test cases, that would be great validation before the PR goes to review!
tinnitussen commentedon May 26, 2026
@surajksharma07 I can confirm the fix works end to end.
I wrote a unit test that asserts temp: keys are excluded from Firestore writes and confirmed it fails without the patch and passes with it. I also tested end-to-end by mounting the patched file into my Docker container locally: grounded search responses now persist correctly and the SSE stream delivers the text response without errors.
surajksharma07 commentedon Jun 4, 2026
@tinnitussen PR #5841 has landed in main via Copybara (commit a5db346) — thanks for seeing it through to merge, including the CLA signing and the pre-commit fix rounds!
Worth noting what makes this a Firestore-specific gap rather than a systemic one: DatabaseSessionService and SqliteSessionService both route their state writes through _session_util.extract_state_delta(), which at line 48 already has elif not key.startswith(State.TEMP_PREFIX) — temp: keys are excluded before they ever reach the database layer.
FirestoreSessionService had its own ad-hoc session_only_state dict comprehension that only excluded app: and user:, so temp: was never filtered.
The fix aligns the Firestore path with what the other backends have always done, and with what base_session_service._trim_temp_delta_state() already enforces on event deltas.
The fix also covers more than just the GroundingMetadata crash. auth_handler.py stores auth credentials under temp: state keys — before this fix, those could silently persist to Firestore documents, which is a real security concern beyond the serialization error. multimodal_tool_results_plugin.py uses temp:PARTS_RETURNED_BY_TOOLS_ID (another non-serializable blob), so multimodal workflows with Firestore would have hit the same crash path.
Both are now protected by the single-line addition.
Closing this out — the fix is in main and will ship in the next release!