Skip to content

gemini-3.5-flash returns empty candidate (STOP, 0 tokens) when replaying its own thoughtSignatures #1769

Description

@uriva

Description

gemini-3.5-flash with thinking enabled can return a completely empty candidatefinishReason: STOP, a single empty content part, and candidatesTokenCount of 0/undefined (zero generated tokens) — when a multi-turn, tool-calling conversation's own accumulated thoughtSignatures are replayed back to the model in contents.

The same request with the thoughtSignatures removed produces a normal response. So the empty output is triggered by replaying the model's own signed thoughts, not by the visible conversation content.

This is easy to mishandle: an SDK/app that treats "no parts / no text / no function call" as "the model chose to stay silent" will make the assistant appear permanently dead to a waiting user.

Environment

  • Model: gemini-3.5-flash
  • Config: thinkingConfig: { includeThoughts: true, thinkingLevel: "LOW" }, maxOutputTokens: 16000
  • Called via models.generateContent (also reproduces via raw REST :generateContent)
  • SDK: @google/genai 2.10.0

Observed response (shape)

{
  "candidates": [
    { "finishReason": "STOP", "content": { "parts": [ {} ] } }
  ],
  "usageMetadata": { "promptTokenCount": 22649 }
}

candidatesTokenCount is absent (zero tokens generated). Deterministic: 8/8 identical requests return the empty candidate.

What we found (minimized)

  • Strip all thoughtSignatures from the history → normal reply every time.
  • Keep the history but strip only the signatures → normal reply.
  • Bisecting signatures: the signature attached to the last tool_call turn is individually sufficient to trigger the empty candidate; the accumulation of the remaining signatures is also sufficient. So it is partly a specific poisoned signature and partly cumulative.
  • Changing the final user message content does not change the outcome.
  • Because thoughtSignatures are bound to exact byte content, any redaction/rewrite of the surrounding text stops the reproduction — the trigger is the exact signed request.

Reproduction / PII note

We have a byte-exact request payload that reproduces this 8/8 by direct fetch to :generateContent. It contains end-user PII (real chat messages) and a proprietary system prompt, and it cannot be scrubbed without invalidating the thoughtSignatures and losing the repro. I can share the exact reproducing request payload privately with the Gemini/AI team on request (secure channel).

Ask

  1. Is an empty candidate (STOP, zero parts/tokens) on thoughtSignature replay a known/expected failure mode?
  2. Guidance on the correct client behavior when it happens (e.g. retry without signatures?), and whether the API should surface a distinct finishReason/error rather than an empty STOP.

Metadata

Metadata

Assignees

Labels

api:gemini-apipriority: p2Moderately-important priority. Fix may not be included in next release.status:awaiting user responseissues requiring a response from the usertype: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions