Unstable Multi-Turn Image Editing ๐ with Google GenAI SDK Streaming: the Problem and the Fix
Hello!
While implementing multi-turn image editing with Gemini 3 Pro Image (Nano Banana Pro), we ran into a troublesome problem: it worked sometimes and failed other times.
In this article, we share the symptoms, the investigation process, and the solution.
The Symptoms
Environment
Google GenAI SDK library (pip): google-genai 1.56.0
Expected Behavior
- User: ใใใใใๅญ็ซใฎ็ปๅใ็ๆใใฆใ ("Generate an image of a cute kitten")
- Gemini: generates a kitten image
- User: ใใใฎๅญใซใกใฌใใใใใฆใ ("Put glasses on this kitten")
- Gemini: the same kitten, now wearing glasses
What Actually Happened
- User: ใใใใใๅญ็ซใฎ็ปๅใ็ๆใใฆใ ("Generate an image of a cute kitten")
- Gemini: generates an image of a brown kitten
- User: ใใใฎๅญใซใกใฌใใใใใฆใ ("Put glasses on this kitten")
- Gemini: generates an image of a girl wearing glasses


In other words, the model was in a state where it did not "remember" the previously generated image.
The Tricky Part: No Reproducibility
What made this problem especially troublesome was that it worked sometimes and failed other times.
- The same code would succeed or fail depending on timing
- After a server restart, it would stop working for long stretches
- It worked in development but not in staging
When identical code suddenly stops working and you reflexively reach for "let's just restart it," you lose your fixed environment, isolating the problem gets harder, and you end up in the "but it was working a minute ago..." situation. Pinning down the cause took a long time.
Investigating the Cause
How thought_signature Works
Multi-turn image editing in Gemini 3 Pro Image relies on a mechanism called thought_signature.
- When generating an image, the model returns a
thought_signature. - This is roughly 2MB of data that preserves information about the generated image (composition, colors, content, and so on)
- Passing it back in the next turn puts the model in a state where it "remembers" the previous image
According to Google's official documentation:
If you use the official Google Gen AI SDKs and use the chat feature, thought signatures are handled automatically.
So, in short, if you use the SDK's chat feature, it should be managed automatically... or so we thought.
With this thought_signature mechanism, you can avoid what text chat normally requires โ sending the entire history so far on every turn.
The SDK's Chat Session
In our approach, we created a chat session with the Google GenAI SDK's client.aio.chats.create() and sent messages with chat.send_message_stream().
# Create a chat session
chat = client.aio.chats.create(model="gemini-3-pro-preview", config=config)
# Send a message (streaming)
response_stream = await chat.send_message_stream(content_parts)
async for response in response_stream:
# Process the response
...
According to the documentation, thought_signature should be managed automatically with this. In practice, it did not work.
Discovering GitHub Issue #1791
As our investigation progressed, we found a related issue on GitHub.
[Bug] ChatSession history fragmentation when using send_message_stream with Thinking (Gemini 3 Pro)
https://github.com/googleapis/python-genai/issues/1791

According to this issue:
When using Gemini 3 Pro Preview with thinking_config enabled, the ChatSession history becomes fragmented when using send_message_stream. Instead of appending a single model turn with the complete response, the SDK appends multiple model turns corresponding to the streaming chunks.
In short, a bug had been reported where using send_message_stream() causes the chat history to become fragmented.
Expected
[User, Model] # 2 entries
Actual
[User, Model, Model, Model, Model, ...] # multiple Model entries
A history entry gets appended for every streaming chunk, breaking the conversation structure.
Why It "Worked Sometimes and Failed Other Times"
Reading this issue, we could infer why the behavior was intermittent.
- With consecutive requests inside the same server instance, it can work because the session is still in memory
- After a server restart or in a new session, it fails because it tries to resume from the broken history
- The degree of history fragmentation varies with timing and network conditions
This was the cause of the irreproducible behavior.
The Solution
Use the Non-Streaming Version
Following issue #1791, we decided to use send_message_stream() instead of send_message().
# Before (streaming)
response_stream = await chat.send_message_stream(content_parts)
async for response in response_stream:
# process
...
# After (non-streaming)
response = await chat.send_message(content_parts)
# process
...
The Result
After switching to the non-streaming version, multi-turn image editing worked reliably.
- Generate a kitten โ add glasses to the same kitten


- Works the same way no matter how many times we try
- Works even after a server restart
Summary
Problem
Using the Google GenAI SDK's send_message_stream() fragments the chat history, and thought_signature is not managed correctly.
Impact
Multi-turn image editing with Gemini 3 Pro Image becomes unstable (it works sometimes and fails other times).
Solution
send_message_stream()Use send_message() instead.
Side Effects
- Real-time streaming display is no longer possible (affects incremental rendering of text + SVG output, etc.)
- No result is returned until image generation completes
- However, if you separately implement progress sub-messages ("Processing..." and the like), the UX impact is minimal
Going Forward
- Wait for the SDK bug fix
- issue #1791 : monitor its progress
- Consider returning to the streaming version once it is fixed
References
- GitHub Issue #1791 - ChatSession history fragmentation
- Google GenAI Python SDK
- Gemini API Image Generation Documentation
Closing Thoughts
Bugs where identical code "works sometimes and fails other times" are extremely hard to pin down. In this case, it took us a while before we thought to suspect the SDK's internal behavior.
We hope this helps anyone struggling with the same problem.
See you next time!