Skip to content

TypeError in convert_if_exist_pydantic_model with parameterized generic types #2013

@tobert

Description

@tobert

Description

When automatic function calling processes a function with a parameterized generic type annotation (e.g., set[str]), the SDK raises TypeError: isinstance() argument 2 cannot be a parameterized generic.

Note

Apologies, my agent posted before I got to review this, but it seems mostly fine.

Minimal Reproduction

from google.genai._extra_utils import convert_if_exist_pydantic_model

# Simulating what happens when Gemini returns a value for a set[str] parameter
result = convert_if_exist_pydantic_model(
    value=['a', 'b'],           # Gemini returns list (JSON array)
    annotation=set[str],        # But annotation is set[str]
    param_name='items',
    func_name='my_func'
)
# TypeError: isinstance() argument 2 cannot be a parameterized generic

Cause

In _extra_utils.py, the function convert_if_exist_pydantic_model() has two locations where isinstance() is called with an annotation that could be a GenericAlias:

Line 257 (inside Union handling):

or isinstance(value, arg)

Line 279 (final fallback):

if not isinstance(value, annotation):

In Python, isinstance(x, set[str]) raises TypeError because set[str] is a GenericAlias, not a type. The SDK correctly handles list[T] and dict[K,V] with special cases using get_origin(), but other parameterized generics fall through to the raw isinstance() call.

Affected Versions

  • google-genai 1.60.0
  • google-genai 1.61.0

Environment

  • Python 3.12
  • Linux

Proposed Fix

Add a helper function that safely handles parameterized generics:

def _safe_isinstance(value: Any, annotation: Any) -> bool:
    """Check isinstance, handling GenericAlias types like set[str]."""
    origin = get_origin(annotation)
    if origin is not None:
        return isinstance(value, origin)
    try:
        return isinstance(value, annotation)
    except TypeError:
        return False

Then replace:

  • Line 257: isinstance(value, arg)_safe_isinstance(value, arg)
  • Line 279: isinstance(value, annotation)_safe_isinstance(value, annotation)

This follows the same pattern already used for list[T] and dict[K,V] at lines 239 and 245.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions