Description
gemini-3.5-flash with thinking enabled can return a completely empty candidate — finishReason: 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
- Is an empty candidate (
STOP, zero parts/tokens) on thoughtSignature replay a known/expected failure mode?
- 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.
Description
gemini-3.5-flashwith thinking enabled can return a completely empty candidate —finishReason: STOP, a single empty content part, andcandidatesTokenCountof 0/undefined (zero generated tokens) — when a multi-turn, tool-calling conversation's own accumulatedthoughtSignatures are replayed back to the model incontents.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
gemini-3.5-flashthinkingConfig: { includeThoughts: true, thinkingLevel: "LOW" },maxOutputTokens: 16000models.generateContent(also reproduces via raw REST:generateContent)@google/genai2.10.0Observed response (shape)
{ "candidates": [ { "finishReason": "STOP", "content": { "parts": [ {} ] } } ], "usageMetadata": { "promptTokenCount": 22649 } }candidatesTokenCountis absent (zero tokens generated). Deterministic: 8/8 identical requests return the empty candidate.What we found (minimized)
thoughtSignatures from the history → normal reply every time.tool_callturn 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.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
fetchto:generateContent. It contains end-user PII (real chat messages) and a proprietary system prompt, and it cannot be scrubbed without invalidating thethoughtSignatures and losing the repro. I can share the exact reproducing request payload privately with the Gemini/AI team on request (secure channel).Ask
STOP, zero parts/tokens) onthoughtSignaturereplay a known/expected failure mode?STOP.