Skip to content

[Gemini 3 Flash Preview] Inconsistent thought_signature generation in parallel function calls causes 400 errors #1275

Description

@peterbherman

Is this a client library issue or a product issue?

This is a PRODUCT ISSUE (Gemini 3 Flash Preview API behavior), not a client library issue. The client library is working correctly - we've verified this with extensive debug logging showing the raw API responses. However, filing here as the Gemini API is the underlying product for this SDK.


Environment details

  • Programming language: TypeScript/JavaScript (Node.js)
  • OS: Linux
  • Language runtime version: Node.js (via Vertex AI)
  • Package version: @google/genai v1.38.0
  • Model: gemini-3-flash-preview
  • API: Vertex AI
  • Region: global

Steps to reproduce

Summary

Gemini 3 Flash Preview inconsistently generates thought_signature fields for parallel function calls. When 3+ tools are called, only the first 1-2 receive signatures, causing subsequent 400 INVALID_ARGUMENT errors when returning function results.

Reproduction Steps

  1. Configure Vertex AI with gemini-3-flash-preview model (global region)
  2. Define 3 or more function/tool declarations
  3. Send a prompt that triggers 3+ parallel function calls via generateContentStream
  4. Capture raw API response - observe only first 1-2 tool calls have thought_signature field
  5. Return all function results (with signatures where provided)
  6. Result: 400 INVALID_ARGUMENT error: "Unable to submit request because function call <name> in the X. content block is missing a thought_signature"

Evidence

Test Case 1: User request requiring 3 data operations

Google's Raw Response (3 parallel tool calls):

{
  "toolCalls": [
    {
      "toolName": "get_resource_list",
      "hasThoughtSignatureField": true,
      "thoughtSignatureValue": "CiEBjz1rX0ilumvPg6k0sMMUtISoQCLJv2bPJ7Vv9r+Xw0o=",
      "thoughtSignatureLength": 48
    },
    {
      "toolName": "get_detailed_results", 
      "hasThoughtSignatureField": true,
      "thoughtSignatureValue": "CiEBjz1rX0ilumvPg6k0sMMUtISoQCLJv2bPJ7Vv9r+Xw0o=",
      "thoughtSignatureLength": 48
    },
    {
      "toolName": "analyze_data",
      "hasThoughtSignatureField": false,
      "thoughtSignatureValue": undefined
    }
  ]
}

Result: ✅ Position 1-2 have signatures | ❌ Position 3 missing → 400 error

Error:

Unable to submit request because function call `analyze_data` 
in the 6. content block is missing a `thought_signature`.

Test Case 2: Different prompt, same 3 tools

Google's Raw Response:

{
  "toolCalls": [
    {
      "toolName": "analyze_data",
      "hasThoughtSignatureField": true,
      "thoughtSignatureValue": "CiEBjz1rX0ilumvPg6k0sMMUtISoQCLJv2bPJ7Vv9r+Xw0o=",
      "thoughtSignatureLength": 48
    },
    {
      "toolName": "get_detailed_results",
      "hasThoughtSignatureField": false,
      "thoughtSignatureValue": undefined
    },
    {
      "toolName": "get_resource_list",
      "hasThoughtSignatureField": false,
      "thoughtSignatureValue": undefined
    }
  ]
}

Result: ✅ Position 1 has signature | ❌ Position 2-3 missing → 400 error


Key Finding: Position-Based Bug

The tool get_resource_list:

  • ✅ HAD signature in Test Case 1 (position 1)
  • ❌ NO signature in Test Case 2 (position 3)

This proves it's position-based, not tool-specific.


Pattern Summary

Test Total Tools Signatures Provided Failed On
1 3 Position 1-2 only Position 3
2 3 Position 1 only Position 2

Gemini 3 Flash generates signatures for ~first 1-2 tool calls, then stops. The cutoff is non-deterministic.


Debug Logs

Raw logs from production showing API response directly from SDK:

[llm] 2026-01-23 16:19:40 [debug]: [RAW GOOGLE RESPONSE] Tool call received
{"toolName":"analyze_data","hasThoughtSignatureField":true,
 "thoughtSignatureValue":"CiEBjz1rX0ilumvPg6k0sMMUtISoQCLJv2bPJ7Vv9r+Xw0o="}

[llm] 2026-01-23 16:19:40 [debug]: [RAW GOOGLE RESPONSE] Tool call received
{"toolName":"get_detailed_results","hasThoughtSignatureField":false}

[llm] 2026-01-23 16:19:41 [debug]: [RAW GOOGLE RESPONSE] Tool call received
{"toolName":"get_resource_list","hasThoughtSignatureField":false}

Implementation Verification

We've ruled out client library issues by:

✅ Capturing thought signatures from streaming responses correctly
✅ Preserving signatures through tool execution lifecycle
✅ Returning signatures byte-for-byte to the API
✅ Extensive debug logging at every step
✅ Confirming with raw API response logs that Google doesn't send all signatures

The same implementation works flawlessly with gemini-2.5-flash, proving this is a Gemini 3 API issue.


Impact

  • Severity: Critical - prevents production use with multi-tool scenarios
  • Scope: Any application using Gemini 3 Flash with 3+ parallel function calls
  • Frequency: Consistent when 3+ tools called
  • Reliability: Non-deterministic cutoff makes failures unpredictable

Workaround

Use gemini-2.5-flash - it doesn't use thought signatures and handles parallel function calls reliably.


Questions

  1. Why are thought signatures inconsistently generated for parallel function calls?
  2. Is this a known limitation of the preview API?
  3. What is the intended maximum number of parallel function calls with thought signatures?
  4. Is there a timeline for fixing this?
  5. Should Gemini 3 Flash be considered production-ready for function calling?

Additional Context

We have extensive debug logs, raw API responses, and reproduction code available. Happy to provide additional evidence or collaborate on debugging.

This bug makes Gemini 3 Flash unsuitable for production use with multi-tool function calling.

Metadata

Metadata

Assignees

Labels

asset: toolDEE Asset tagging - Tool.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions