googleapis / googleapis/python-genai
gemini-3.5-flash with generate_content_stream + automatic function calling stops after tool execution and returns empty final text
- Dominant language
- Python
- Stars
- 4k
- Forks
- 1k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 40
Description
## Summary
When using `gemini-3.5-flash` with `generate_content_stream` and automatic function calling enabled, the model executes a tool successfully but then ends the stream with:
- `finish_reason = STOP`
- final candidate content containing only `{"text": ""}`
- no visible text
- no `automatic_function_calling_history`
The same workflow works with `gemini-2.5-flash`, and the same logical flow works if we do not rely on AFC streaming.
## Date observed
June 9, 2026
## Environment
- Python SDK: `google-genai 2.8.0`
- Model: `gemini-3.5-flash`
- Method: `client.models.generate_content_stream(...)`
- Automatic function calling enabled
- Python 3.11
- Also reproduced previously with `google-genai 1.50.0`
## Scenario
We have a tool-based structured-data agent. The expected flow is:
1. model calls a discovery tool
2. tool returns a valid candidate
3. model either continues tool usage or emits final text
In this case, step 2 succeeds, but the model immediately ends the stream with an empty final text candidate.
## Minimal observed behavior
User question:
```text
What is the birth rate for SampleTown in 2023?
```
Tool call executed successfully:
```
find_metric_candidates(query="birth rate")
```
Tool result:
```json
{
"query": "birth rate",
"result": [
{
"id": 101,
"name": "Crude birth rate",
"dataset": "public_metrics_table",
"metric_type": 1,
"geo_levels": "City, Region, Country",
"match_source": "name_contains"
}
],
"row_count": 1
}
```
But the stream ends with:
```json
{
"content": {
"parts": [
{
"text": ""
}
],
"role": "model"
},
"finish_reason": "STOP",
"index": 0
}
```
No visible text is produced.
## Expected behavior
After a successful tool call, the model should either:
- continue with additional tool calls, or
- emit a final visible text response
It should not end with `STOP` and an empty text-only candidate.
## Actual behavior
- tool executes successfully
- stream returns HTTP 200
- final chunk has `finish_reason=STOP`
- final candidate has `text=""`
- no `automatic_function_calling_history`
- no visible output
## Sanitized diagnostic logs
```
HTTP Request: POST .../models/gemini-3.5-flash:streamGenerateContent?alt=sse "HTTP/1.1 200 OK"
[Tool] find_metric_candidates called
[Tool] query: birth rate
[Tool] returned 1 row
[DIAG] chunk=1 text_len=0 has_history=False finish_reason=FinishReason.STOP parts=['empty_text']
[DIAG RAW] candidate={'content': {'parts': [{'text': ''}], 'role': 'model'}, 'finish_reason': 'STOP', 'index': 0}
```
## Comparison
- `gemini-2.5-flash` works correctly in the same agent/tool flow
- `gemini-3.5-flash` fails in AFC streaming mode
- similar behavior was observed across multiple Gemini 3 family models in this workflow
## Workarounds tried
- prompt changes
- thinking configuration changes
- SDK upgrade from `1.50.0` to `2.8.0`
The issue still reproduces in AFC streaming mode.
## Question
- Is this a known limitation or bug in `gemini-3.5-flash` with `generate_content_stream` + automatic function calling?
- If this is expected behavior, what is the recommended pattern for Gemini 3.5 in this scenario?
Contributor guide
Assessment
This issue has not been assessed yet.