Skip to content

Commit 1e27d79

Browse files
authored
fix(gemini): Gemini UnboundLocal Exception raised during stream (#1420)
1 parent 08bf563 commit 1e27d79

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

src/strands/models/gemini.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ async def stream(
426426
yield self._format_chunk({"chunk_type": "content_start", "data_type": "text"})
427427

428428
tool_used = False
429+
candidate = None
430+
event = None
429431
async for event in response:
430432
candidates = event.candidates
431433
candidate = candidates[0] if candidates else None
@@ -455,7 +457,8 @@ async def stream(
455457
"data": "TOOL_USE" if tool_used else (candidate.finish_reason if candidate else "STOP"),
456458
}
457459
)
458-
yield self._format_chunk({"chunk_type": "metadata", "data": event.usage_metadata})
460+
if event:
461+
yield self._format_chunk({"chunk_type": "metadata", "data": event.usage_metadata})
459462

460463
except genai.errors.ClientError as error:
461464
if not error.message:

tests/strands/models/test_gemini.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,25 @@ async def test_stream_response_none_candidates(gemini_client, model, messages, a
566566
assert tru_chunks == exp_chunks
567567

568568

569+
@pytest.mark.asyncio
570+
async def test_stream_response_empty_stream(gemini_client, model, messages, agenerator, alist):
571+
"""Test that empty stream doesn't raise UnboundLocalError.
572+
573+
When the stream yields no events, the candidate variable must be initialized
574+
to None to avoid UnboundLocalError when referenced in message_stop chunk.
575+
"""
576+
gemini_client.aio.models.generate_content_stream.return_value = agenerator([])
577+
578+
tru_chunks = await alist(model.stream(messages))
579+
exp_chunks = [
580+
{"messageStart": {"role": "assistant"}},
581+
{"contentBlockStart": {"start": {}}},
582+
{"contentBlockStop": {}},
583+
{"messageStop": {"stopReason": "end_turn"}},
584+
]
585+
assert tru_chunks == exp_chunks
586+
587+
569588
@pytest.mark.asyncio
570589
async def test_stream_response_throttled_exception(gemini_client, model, messages):
571590
gemini_client.aio.models.generate_content_stream.side_effect = genai.errors.ClientError(

0 commit comments

Comments
 (0)