> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How Do I Fix Gemini Thought Signature 400 Errors in Tool Calls?

> With Gemini 3 and later models, 'Function call is missing a thought_signature' means your client dropped the signature when replaying history; 'Invalid / Corrupted thought signature' means the signature failed validation on the current route. How to tell them apart and fix each.

## Short Answer

When Gemini 3 and later models (gemini-4-argon, gemini-3.8-flash, gemini-3.1-pro-preview, and so on) run multi-turn function calling, there are two kinds of 400 errors related to the thought signature (`thoughtSignature`), and they need different fixes:

| Error text | Meaning | Fix |
| - | - | - |
| `Function call is missing a thought_signature in functionCall parts` | **Your request has no signature.** The `thoughtSignature` field was dropped from the previous turn's `functionCall` part when the history was replayed | Fix the client: put the model's previous reply back into the history **verbatim**; do not rebuild the part |
| `Invalid thought signature` / `Corrupted thought signature` | **A signature was sent, but it failed validation on the current route.** Usually the conversation switched route, model, key, or group midway | Resend once as is; if it still fails, strip `thoughtSignature` from the history turns and resend, or start a new conversation |

If you call through the OpenAI-compatible `/v1/chat/completions` endpoint, **none of this applies to you**: the gateway manages signatures, and standard `tool_calls` / `tool` messages are all you need.

## Telling the Two Errors Apart

### Missing signature

```text theme={null}
400 Function call is missing a thought_signature in functionCall parts.
This is required for tools to work correctly, and missing thought_signature
may lead to degraded model performance. Additional data, function call
`default_api:Bash`, position 2.
```

The message names the function and its index in the `parts` array. This is a hard rule enforced by the model provider for the Gemini 3 family: **every `functionCall` part in the current turn must carry its signature.** A missing one fails with 400 on every route, and retrying does not help.

### Invalid or corrupted signature

```text theme={null}
400 Invalid thought signature.
400 Corrupted thought signature.
```

The field is present but fails validation. The signature is an encrypted blob that **only the route that generated it can verify**. If the conversation switches route, model, key, or group midway, earlier signatures may no longer be accepted.

## Why This Happens

When tools are enabled, Gemini 3 models attach an encrypted `thoughtSignature` to the same part as each `functionCall`, recording the reasoning state at that step. On the next request the model needs it to continue the reasoning chain, so the provider requires it to be sent back unchanged.

<CardGroup cols={2}>
  <Card title="Missing: the client rebuilt the part" icon="file-x">
    The most common cause. A custom framework or middleware keeps only the `name` and `args` of the `functionCall` when assembling history and drops the sibling `thoughtSignature`; or streaming chunks are reassembled without merging the signature in.
  </Card>

  <Card title="Missing: history was compressed or rewritten" icon="scissors">
    The client trimmed or summarized the context, or merged several parts into one, and the signature went with it.
  </Card>

  <Card title="Invalid: route changed mid-conversation" icon="shuffle">
    The first turns were served by route A and later turns landed on route B, which does not recognize A's signatures. The switch can come from you changing group or key, or from automatic failover.
  </Card>

  <Card title="Invalid: model changed mid-conversation" icon="layers">
    Starting on gemini-3.8-flash and switching to gemini-4-argon within the same conversation. Signatures are not portable across models.
  </Card>
</CardGroup>

<Info>
  For parallel function calls the model attaches a signature only to the **first** `functionCall` part; the others legitimately have none, so do not fabricate one. For sequential calls (several steps within one turn) every step carries a signature and every one must be returned.
</Info>

## Fix 1: Missing Signature, Change How the Client Replays History

<Steps>
  <Step title="Put the whole model reply back verbatim">
    With the official `google-genai` SDK, simply `contents.append(response.candidates[0].content)`; do not extract only the `function_call` field. In hand-written REST, the model turn in the second request's `contents` must look like this:

    ```json theme={null}
    {
      "role": "model",
      "parts": [
        {
          "functionCall": { "name": "lookup_order", "args": { "order_id": "B5001" } },
          "thoughtSignature": "AY89..."
        }
      ]
    }
    ```

    `thoughtSignature` and `functionCall` are **two fields of the same part**, not two parts.
  </Step>

  <Step title="Check whether a framework or middleware strips the field">
    With LangChain, a custom agent framework, or an OpenAI-to-Gemini translation layer, print the actual request body of the second turn and confirm `thoughtSignature` is still there. The `position N` in the error is `parts[N]`; look there directly.
  </Step>

  <Step title="Do not rely on some models letting it through">
    Models and routes differ in how strictly they enforce missing signatures: some let it pass, others return 400. If the same code has always worked on gemini-3.8-flash and breaks on gemini-4-argon, the signature was most likely never sent and was merely tolerated before. Returning signatures as the provider requires is stable on every model.
  </Step>
</Steps>

## Fix 2: Invalid Signature, Resend or Start Over

<Steps>
  <Step title="Resend once as is">
    When the APIYI gateway receives a signature 400 it automatically retries on another route, so a plain resend often succeeds. No changes needed.
  </Step>

  <Step title="Still 400: strip signatures from history turns and resend">
    Remove the `thoughtSignature` field from the parts of every `role: "model"` turn in the history, then resend. You lose the reasoning context of those turns and answer quality may dip slightly, but the conversation can continue. Only strip history turns, never the current one.
  </Step>

  <Step title="Or start a new conversation">
    The simplest and most reliable option. In a new conversation every signature comes from the same route from the first turn on.
  </Step>

  <Step title="One model, one key per conversation">
    When you need to switch model, key, or group, start a new conversation first. Do not switch inside a conversation that already has tool-call history.
  </Step>
</Steps>

## No Signature Handling on the OpenAI-Compatible Endpoint

When you call Gemini through `/v1/chat/completions`, `tool_calls` messages have no signature field; the gateway saves and restores it during translation. In our tests on gemini-4-argon, two-turn conversations passed for all three shapes: a single call, two parallel calls, and text plus a call. Just return `tool_calls` and `tool` messages the standard OpenAI way.

<Note>
  Clients such as Codex that default to `/v1/responses` need to switch to the chat protocol, since Gemini models do not support that endpoint yet. See [Gemini 4 Argon Text Generation](/en/api-capabilities/gemini-4-argon/overview).
</Note>

## FAQ

<AccordionGroup>
  <Accordion title="Only argon throws this; flash has always been fine. Is argon broken?">
    No. Returning signatures is the provider's requirement for the whole Gemini 3 family; some models' routes are simply lenient about missing ones. Moving to a strictly validating model exposes the problem, but the root cause is still a client that never sent the signature.
  </Accordion>

  <Accordion title="Can I cache a signature and reuse it across conversations?">
    No. A signature is valid only on the route and within the conversation context that produced it. Copying it into another conversation yields Invalid.
  </Accordion>

  <Accordion title="Where is the signature in a streaming response?">
    In the same part as the `functionCall`, inside the chunk that carries it. When reassembling the stream, merge this field together with `functionCall` into the final model reply before putting it back into history.
  </Accordion>

  <Accordion title="Do plain-text turns need signatures too?">
    Not strictly. The provider hard-validates signatures only on `functionCall` parts; a missing signature on a text turn does not 400, but keeping it helps reasoning continuity, so return the whole reply verbatim anyway.
  </Accordion>
</AccordionGroup>

## Related Docs

<CardGroup cols={2}>
  <Card title="Gemini Function Calling Guide" icon="code" href="/en/api-capabilities/gemini/function-calling">
    Full two-turn example, including how to return signatures
  </Card>

  <Card title="Gemini 4 Argon Text Generation" icon="sparkles" href="/en/api-capabilities/gemini-4-argon/overview">
    Multi-turn tool-call notes and client setup
  </Card>

  <Card title="How Do I Fix Claude's Invalid Thinking Signature Error?" icon="file-signature" href="/en/faq/claude-thinking-signature-invalid">
    The same class of problem on the Claude side
  </Card>

  <Card title="Multi-Turn Conversation Guide" icon="messages-square" href="/en/api-capabilities/multi-turn-conversation">
    How each provider expects history to be returned
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.