Skip to content

RecursionError in _to_gemini_schema() when processing circular $ref in $defs #3870

Closed

Description

@foivos-all

Describe the bug
The _to_gemini_schema() function in google.adk.tools._gemini_schema_util triggers a RecursionError when processing JSON Schemas with circular $ref references in $defs. The _dereference_schema() helper function recursively resolves these references without detecting circular dependencies, causing infinite recursion.

To Reproduce

  • Minimal code to reproduce the issue:
    from google.adk.tools._gemini_schema_util import _to_gemini_schema
    
    # Schema with circular reference: Attendee -> alternateAttendee -> Attendee
    schema_with_circular_refs = {
        "type": "object",
        "properties": {
            "body": {
                "type": "object",
                "properties": {
                    "attendees": {
                        "type": "array",
                        "items": {"$ref": "#/$defs/Attendee"}
                    },
                    "end": {"$ref": "#/$defs/DateTimeTimeZone"}
                }
            }
        },
        "$defs": {
            "DateTimeTimeZone": {
                "type": "object",
                "properties": {
                    "dateTime": {"type": "string"},
                    "timeZone": {"type": "string"}
                }
            },
            "Attendee": {
                "type": "object",
                "properties": {
                    "proposedNewTime": {
                        "type": "object",
                        "properties": {
                            "start": {"$ref": "#/$defs/DateTimeTimeZone"},
                            "end": {"$ref": "#/$defs/DateTimeTimeZone"}
                        }
                    },
                    "alternateAttendee": {"$ref": "#/$defs/Attendee"}
                }
            }
        },
        "required": ["body"]
    }
    
    # This will trigger a RecursionError
    gemini_schema = _to_gemini_schema(schema_with_circular_refs)
    
  • Steps to reproduce:
    1. Install google-adk and google-genai
    2. Run the code above
    3. Observe RecursionError: maximum recursion depth exceeded

Expected behavior

  • The function should either:

    1. Detect circular references and raise a clear, descriptive error (e.g., ValueError: Circular reference detected in schema at path ...)
    2. Handle circular references gracefully by tracking visited definitions during dereferencing
  • Stack trace:

       [...]
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 94, in _resolve_refs
         return _resolve_refs(resolved)
                ^^^^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 94, in _resolve_refs
         return _resolve_refs(resolved)
                ^^^^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 94, in _resolve_refs
         return _resolve_refs(resolved)
                ^^^^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       [Previous line repeated 1 more time]
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 94, in _resolve_refs
         return _resolve_refs(resolved)
                ^^^^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
       File "/home/ubuntu/venv/lib/python3.12/site-packages/google/adk/tools/_gemini_schema_util.py", line 100, in _resolve_refs
         return {key: _resolve_refs(value) for key, value in sub_schema.items()}
                      ^^^^^^^^^^^^^^^^^^^^
     RecursionError: maximum recursion depth exceeded
    

Desktop (please complete the following information):

  • OS: Linux (Ubuntu)
  • Python version(python -V): Python 3.12.3
  • ADK version(pip show google-adk):
    • google-adk==1.20.0
    • google-genai==1.54.0

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used(e.g. gemini-2.5-pro): N/A (error occurs during schema conversion, before model invocation)

Additional Context
This issue was discovered while building an MCP server tool that uses schemas with legitimate circular references for recursive data structures (for example, attendees with alternate attendees)

  • The root cause appears to be in _dereference_schema(), which currently does not perform cycle detection when recursively resolving $ref pointers in $defs
  • A previous attempt was made to fix this in google-genai, but that change could not be merged because the affected file (types.py) is dynamically generated
  • I was advised to raise an issue (and potentially a PR) here; once I figure out an appropriate approach, I am happy to follow up with a PR

Activity

  1. added
    tools[Component] This issue is related to tools
    mcp[Component] This issues is related to MCP support
    on Dec 8, 2025
  2. added theissue type on Dec 8, 2025
  3. xuanyang15 commented on Dec 15, 2025

    @xuanyang15
    Collaborator

    Hi @foivos-all, thanks for reporting this issue! We are actually migrating Function Tool Declaration from parameters to paramters_json_schema, which will deprecate the usage of _to_gemini_schema. Could you please try the new code path without _to_gemini_schema? You can enable it by setting env variable ADK_ENABLE_JSON_SCHEMA_FOR_FUNC_DECL=1.

  4. self-assigned this
    on Dec 15, 2025
  5. foivos-all commented on Dec 16, 2025

    @foivos-all
    ContributorAuthor

    Hi @xuanyang15, I tested it and it seems to work. Thanks! Greatly appreciated. I added a PR to fix the _to_gemini_schema function. If you're keeping the _to_gemini_schema code path, feel free to review and merge it, or I can keep it till it's phased out completely. Let me know which works best for you and the team.

    Additionally, I saw that you added a function called override_feature_enabled in a088506 to override the default and not have to worry about setting environment variables. Any idea on when the package in PyPI might be updated with this new change?

  6. xuanyang15 commented on Dec 16, 2025

    @xuanyang15
    Collaborator

    @foivos-all Thanks for helping verify the feature! Let's keep the PR until the new code path is finally phased out completely.

    Actually, I'm also working on adding a cli flag (e.g. --enable_features) which relies on the override_feature_enabled, you probably can use it instead of the override_feature_enabled if you are using ADK CLI. Anyway, both of them should be available in next ADK release (v1.22.0, eta. early Jan after the holiday freeze).

  7. adk-bot commented on Jan 7, 2026

    @adk-bot
    Collaborator

    This issue has been automatically marked as stale because it has not had recent activity for 7 days after a maintainer requested clarification. It will be closed if no further activity occurs within 7 days.

  8. added
    stale[Status] Issues which have been marked inactive since there is no user response
    request clarification[Status] The maintainer need clarification or more information from the author
    on Jan 7, 2026
  9. adk-bot commented on Jan 14, 2026

    @adk-bot
    Collaborator

    This has been automatically closed because it has been marked as stale for over 7 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

mcp[Component] This issues is related to MCP supportrequest clarification[Status] The maintainer need clarification or more information from the authorstale[Status] Issues which have been marked inactive since there is no user responsetools[Component] This issue is related to tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions