Repository navigation
FunctionDeclaration doesn't support dicts #5364
Copy link
Copy link
Closed
Labels
tools[Component] This issue is related to tools[Component] This issue is related to tools
Description
Describe the Bug:
Python methods with dicts in signature raises issues when FunctionTool tries to come up with schema.
Complex types as list/dict are handled in fallback branch relying on pydantic.TypeAdapter.json_schema(), that emits additionalProperties for typed dicts.
Follow-up for #4798
Steps to Reproduce:
Please provide a numbered list of steps to reproduce the behavior:
import asyncio
import os
from datetime import datetime, timezone
from google.adk import Agent, Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types as genai_types
APP_NAME = "repro"
USER_ID = "u1"
MODEL = "gemini-2.5-flash"
async def get_utc_timestamp(
options: dict[str, str] | None = None,
# options: list[str] | None = None,
) -> str:
_ = options
return datetime.now(timezone.utc).isoformat()
async def main() -> None:
agent = Agent(
name="time_agent",
model=MODEL,
instruction="You are a helpful assistant. Use tools when asked for the time.",
tools=[get_utc_timestamp],
)
session_service = InMemorySessionService()
session = await session_service.create_session(app_name=APP_NAME, user_id=USER_ID)
runner = Runner(app_name=APP_NAME, agent=agent, session_service=session_service)
user_msg = genai_types.Content(
role="user",
parts=[genai_types.Part(text="What's the current UTC timestamp?")],
)
async for event in runner.run_async(
user_id=USER_ID, session_id=session.id, new_message=user_msg
):
if event.content and event.content.parts and event.is_final_response():
for part in event.content.parts:
print(part.text)
if __name__ == "__main__":
os.environ.setdefault("GOOGLE_API_KEY", "<your key here>")
asyncio.run(main())
Expected Behavior:
dict should be recognized in Schema.
Observed Behavior:
google.genai.errors.ClientError: 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': 'Invalid JSON payload received. Unknown name "additional_properties" at \'tools[0].function_declarations[0].parameters.properties[0].value.any_of[0]\': Cannot find field.', 'status': 'INVALID_ARGUMENT', 'details': [{'@type': 'type.googleapis.com/google.rpc.BadRequest', 'fieldViolations': [{'field': 'tools[0].function_declarations[0].parameters.properties[0].value.any_of[0]', 'description': 'Invalid JSON payload received. Unknown name "additional_properties" at \'tools[0].function_declarations[0].parameters.properties[0].value.any_of[0]\': Cannot find field.'}]}]}}
Environment Details:
- ADK Library Version (pip show google-adk): 1.31.0
- Desktop OS: macOS
- Python Version (python -V): Python 3.11.14
Model Information:
- Are you using LiteLLM: No
- Which model is being used: gemini-2.5-flash
How often has this issue occurred?:
- Always (100%)
Reactions are currently unavailable
Metadata
Metadata
Labels
tools[Component] This issue is related to tools[Component] This issue is related to tools
Activity
perrymanuk commentedon Apr 18, 2026
Confirming this reproduces in a production setting (
google-adk==2.0.0a3,google-genai==1.72.0, Python 3.14) with a few extra data points that may help narrow it down:Model-dependent strictness
The failure only surfaces on
gemini-2.5-flashandgemini-3.1-flash. The identical agent + tools + schema ran againstgemini-3.1-pro-previewfor weeks without issue —prowas tolerating the unknownadditional_propertiesfield silently.In our case the bug was latent after the ADK 2.x upgrade but only started 400-ing once we downgraded our orchestrator from pro to flash for cost reasons. That means other users may be sitting on this without realising, and any model-tier downshift in a multi-agent app is likely to surface it.
Also triggered by
Optional[List[...]]Not just dicts —
Optional[List[str]]parameters hit the same fallback branch and produce the same snake_case leak. Our failing schemas included:attendees: Optional[List[str]](calendar event tool)related_refs: Optional[List[str]]metadata: Optional[Dict[str, Any]]metadata_merge: Optional[Dict[str, Any]]related_info: Optional[Dict[str, Any]]All five shapes produced the same
Unknown name "additional_properties" at '...any_of[0]'400 when routed to flash.Workaround for anyone blocked
A small
before_model_callbackthat recursively strips the non-standard key from every outgoingllm_request.config.tools[*].function_declarations[*].parametersis working reliably as a holdover. The camelCaseadditionalProperties(standards-compliant) is left untouched; only the snake_case one is removed:https://github.com/perrymanuk/radbot/blob/main/radbot/callbacks/sanitize_tool_schemas.py
Wired onto the root agent + every sub-agent via
before_model_callbackso the scrub runs on every LLM call. Idempotent and becomes a harmless no-op once the upstream fix lands.Note on #5052
FWIW #5052 appears to explicitly emit the snake_case
additional_propertieskey in the dict branch, which is the opposite direction from what the Gemini API accepts (it requires camelCaseadditionalPropertiesper standard JSON Schema). May be worth double-checking that PR's output against the REST validator before merging — the repro in this issue would presumably still 400 after #5052 lands.EugeneYushin commentedon Apr 20, 2026
Thanks @perrymanuk for a thorough review.
It fails for me with
gemini-3.1-pro-previewas well. I'm able to reproduce the issue puttingpromodel in repro steps.I'm calling _sanitize_schema_formats_for_gemini in my PR fix, but most probably we will loose key type hints that way (judging by #5052).
klateefa commentedon Apr 23, 2026
@pp-eyushin This seems to be a
schema formattingissue, not a limitation withdict itself. The generated schema includesadditional_properties(snake_case), which isn’t validJSON Schema, so Gemini rejects it. It expects additionalProperties (camelCase).Fix is to clean or normalize the schema before sending it, or avoid raw dict types and useexplicit models. PR #5366 looks like it addresses this by sanitizing the schema. Can you try this and let me know if the issue persists?pp-eyushin commentedon Apr 23, 2026
@klateefa yes, PR you mention fixes the issue.
surajksharma07 commentedon Jun 9, 2026
/adk-issue-analyze
fix: call to sanitize schema for complex union types
GWeale commentedon Jun 17, 2026
Fixed on main via #5366 (commit 9808451): the generated schema for complex union/dict types is now sanitized, so dict-typed FunctionDeclaration params no longer 400 on Gemini. Closing as fixed.
fix: call to sanitize schema for complex union types