Skip to content

FunctionTool automatic parsing fails on list[tuple[bytes, str]] parameter type #5428

Closed

Description

@kaligautier

🔴 Required Information

Describe the Bug:
FunctionTool automatic function declaration parsing crashes at startup when a tool function has a parameter typed list[tuple[bytes, str]] | None. The error originates from _function_parameter_parse_util._raise_for_unsupported_param after Pydantic's Schema.model_validate rejects the generated schema with Extra inputs are not permitted.

This prevents the agent from starting entirely — it's not a runtime error but a startup crash during tool declaration building.

Steps to Reproduce:

  1. Define a tool function with a complex parameter type:
from google.adk.tools import ToolContext
from google.adk.tools.function_tool import FunctionTool

async def generate_image(
    prompt: str,
    input_bytes: list[tuple[bytes, str]] | None = None,
    tool_context: ToolContext = None,
) -> dict:
    """Generate an image from a prompt."""
    return {"status": "success"}

generate_image_tool = FunctionTool(func=generate_image)
  1. Register the tool on an LlmAgent and start the agent (e.g. via A2A executor or Runner).

  2. The agent crashes during _preprocess_async → _process_agent_tools → tool._get_declaration():

Expected Behavior:
Either:

  • ADK should support tuple types in function signatures by mapping them to a JSON Schema array with prefixItems, or
  • ADK should provide a clear, documented mechanism to exclude specific parameters from automatic declaration parsing (e.g., an ignore_params option on FunctionTool), or
  • At minimum, the error message should link to documentation on how to implement the manual declaration workaround.

Observed Behavior:
Two chained exceptions:

pydantic_core._pydantic_core.ValidationError: 1 validation error for Schema
  Extra inputs are not permitted [type=extra_forbidden, input_value=[{'format': 'binary', 'ty...g'}, {'type': 'string'}], input_type=list]

Followed by:

ValueError: Failed to parse the parameter input_bytes: list[tuple[bytes, str]] | None = None
of function generate_image for automatic function calling.
Automatic function calling works best with simpler function signature schema,
consider manually parsing your function declaration for function generate_image.

Environment Details:

  • ADK Library Version: 1.26.0
  • Desktop OS: Linux (Cloud Run container) / macOS (local dev)
  • Python Version: 3.12

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: Gemini (via Vertex AI)

🟡 Optional Information

Regression:
N/A — first time using this parameter type.

Logs:

File "/app/.venv/lib/python3.12/site-packages/google/adk/tools/function_tool.py", line 89, in _get_declaration
    build_function_declaration(
  File "/app/.venv/lib/python3.12/site-packages/google/adk/tools/_automatic_function_calling_util.py", line 257, in build_function_declaration
    else from_function_with_options(new_func, variant)
  File "/app/.venv/lib/python3.12/site-packages/google/adk/tools/_automatic_function_calling_util.py", line 368, in from_function_with_options
    _function_parameter_parse_util._raise_for_unsupported_param(
  File "/app/.venv/lib/python3.12/site-packages/google/adk/tools/_function_parameter_parse_util.py", line 101, in _raise_for_unsupported_param
    raise ValueError(
ValueError: Failed to parse the parameter input_bytes: list[tuple[bytes, str]] | None = None of function generate_image

How often has this issue occurred?:

  • Always (100%)

Additional Context:

The use case is an image generation tool where a before_tool callback pre-loads remote images (from GCS, Google Drive, or artifacts) and injects the loaded (bytes, mime_type) pairs into the function args. The LLM never fills these parameters — they are only set programmatically by the callback.

Current workaround: Subclass FunctionTool, override _get_declaration() to return a hand-crafted types.FunctionDeclaration that only exposes LLM-visible parameters (prompt, aspect_ratio, etc.) and omits input_bytes from the schema entirely. This works but is verbose and error-prone.

Suggested improvements (any of):

  1. Support tuple types in _function_parameter_parse_util by mapping to JSON Schema prefixItems.
  2. Expose ignore_params on FunctionTool.__init__ (the internal _ignore_params list already exists but is not public and only covers tool_context/input_stream).
  3. Add a decorator like @adk_hidden to mark parameters that should be excluded from the LLM declaration.

Activity

  1. added
    tools[Component] This issue is related to tools
    on Apr 21, 2026
  2. added theissue type on Apr 21, 2026
  3. surajksharma07 commented on Apr 21, 2026

    @surajksharma07
    Collaborator

    @kaligautier Thanks for the detailed report and for already digging into the root cause — you're right that the fallback path passes a Pydantic-generated schema with prefixItems to types.Schema.model_validate, which rejects it due to extra='forbid'.

    As a lighter workaround while the PR is under review, try patching _generate_json_schema_for_parameter to strip prefixItems/unevaluatedItems before validation.

    Could you give that a try on your end and confirm it holds up in your Cloud Run setup before we move the PR forward?

  4. kaligautier commented on Apr 21, 2026

    @kaligautier
    ContributorAuthor

    @kaligautier Thanks for the detailed report and for already digging into the root cause — you're right that the fallback path passes a Pydantic-generated schema with prefixItems to types.Schema.model_validate, which rejects it due to extra='forbid'.

    As a lighter workaround while the PR is under review, try patching _generate_json_schema_for_parameter to strip prefixItems/unevaluatedItems before validation — happy to share the snippet if that'd be useful.

    Could you give that a try on your end and confirm it holds up in your Cloud Run setup before we move the PR forward?

    can you give me the snippet ? thx ! @surajksharma07

  5. surajksharma07 commented on Apr 22, 2026

    @surajksharma07
    Collaborator

    @kaligautier Drop this before you instantiate your FunctionTool and it'll strip prefixItems/unevaluatedItems from the Pydantic-generated schema before types.Schema sees it:

    from google.adk.tools import _function_parameter_parse_util
    
    _STRIP = frozenset({"prefixItems", "unevaluatedItems"})
    
    def _sanitize(s):
        if not isinstance(s, dict):
            return s
        for k in _STRIP:
            s.pop(k, None)
        for v in s.values():
            if isinstance(v, dict): _sanitize(v)
            elif isinstance(v, list): [_sanitize(i) for i in v if isinstance(i, dict)]
        return s
    
    _orig = _function_parameter_parse_util._generate_json_schema_for_parameter
    _function_parameter_parse_util._generate_json_schema_for_parameter = lambda p: _sanitize(_orig(p))
    

    Also worth a heads-up — PR #5446 just landed from another contributor taking the exact same strip approach but applied directly in the ADK source (_function_parameter_parse_util.py), so there are now two open PRs targeting this.

    Once you've confirmed the snippet holds up in Cloud Run, it'd be great if you could drop a note on whichever PR approach you prefer — it'll help the reviewers know where to focus!

    Team is looking more into it.

    Thanks!

  6. surajksharma07 commented on May 22, 2026

    @surajksharma07
    Collaborator

    @kaligautier — since we haven't heard back after sharing the snippet last month and asking you to verify it in your Cloud Run setup, going ahead and closing this out for now to keep things moving.

    The underlying fix will continue through the open PRs — your #5429 (fallback tuple handling) and @EaCognitive's #5446 (strip-based approach) are both targeting the same root cause, so reviewers can consolidate from there.

    If you do get a chance to test the workaround and confirm it holds, or if you have a preference on which PR approach to push forward, dropping a note on either PR would be really helpful.

    Feel free to reopen if anything changes!

  7. added a commit that references this issue on Jun 22, 2026
    4fa7741
  8. added a commit that references this issue on Aug 11, 2026
    183094e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

request clarification[Status] The maintainer need clarification or more information from the authortools[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