[Bug] Multimodal Live API (v1beta) triggers identical tool calls twice in rapid succession

Hello,

I am building a voice-assistant using the new google-genai Python SDK and the Multimodal Live API (via v1beta). I am streaming Realtime Audio in and out.

I have noticed a recurring bug: Sometimes, when the model decides to use a configured tool (Function Calling), it triggers the exact same

|16pxx16px

tool_calltwice (or multiple times) in rapid succession during the same turn.

Here is the standard way I am receiving the responses:

python

async for response in turn:

# 1. Handle Audio

# 2. Handle Text

# …

# 3. Handle Tool Calls

if tool_call := getattr(response, “tool_call”, None):

await self._handle_tool_call(tool_call)

Inside my

|16pxx16px

_handle_tool_callmethod, I receive the identical function name and arguments twice within a few milliseconds to seconds. This leads to duplicate executions (e.g., executing a smart home command twice or creating duplicate calendar events).

Right now my only workaround is to build a complex manual debounce-filter on the client side that caches the function name and arguments, and ignores identical requests that occur within ~3 seconds of each other.

Is this a known issue with the current preview of the Live API? Is there any recommended best practice to avoid duplicate tool triggers on the server side?

Thank you!

Hi @marcelo7

Could you share which model you are using for this ? Working on reproducing this

Model name: models/gemini-2.5-flash-native-audio-preview-09-2025 API Version: v1beta (Multimodal Live API via WebSockets) SDK: google-genai (Python) version 1.56.0 Context: The issue occurs specifically during live audio streaming where the model identifies a tool call and triggers identical tool calls twice in very rapid succession (almost simultaneously).

Hey, do you have a solution?

Hi

Apologies for the delayed response on this

I tried with a few different iterations but was unable to reproduce this issue

The solution you have used is what i would also recommend , in terms of handling duplicate calls.

A few follows up :
Do you use function calling anywhere else in your application or is this only instance where its been called ( and resulting in duplicate calling )
Would it be possible for you to DM me psuedo code where this is occurring ?

Hi Mustan,

Thank you for your response! To help you reproduce this, here is the context: I am building a Voice Assistant (Smart Mirror) and I’m using the google-genai Python SDK (v1beta).

The issue is that the model often provides a duplicate (but varied) response when a tool is triggered. It seems to “restart” its speech turn once the tool response is received.

Example of the behavior:

  1. User: “My name is Marcelo.”

  2. Model triggers tool: remember_fact(name="Marcelo")

  3. Model starts speaking immediately: “Nice to meet you!”

  4. Tool response is sent back to the session.

  5. Model speaks again (Restart): “Oh, hello Marcelo, nice to meet you!”

Actual Code Implementation: Here is the core of my receive_audio and tool_handling logic from my main.py. This is where the race condition seems to happen:

python

async def receive_audio(self):

“”“Receives and processes responses from Gemini”“”

while True:

if not self.session:

await asyncio.sleep(0.2)

continue

try:

        turn = self.session.receive()

async for response in turn:

# 1. AUDIO DATA - This starts playing immediately

if data := getattr(response, “data”, None):

self.audio_in_queue.put_nowait(data)

self.is_speaking = True

# 2. TOOL CALLS - Triggered in the same turn

if tool_call := getattr(response, “tool_call”, None):

await self._handle_tool_call(tool_call)

# Turn complete logic…

self.is_speaking = False

except Exception as e:

self.log(f"Error in receive_audio: {e}")

async def _handle_tool_call(self, tool_call):

“”“Processes tool calls and sends response back”“”

for fc in tool_call.function_calls:

# Execute the local tool logic

    result = await self.execute_local_logic(fc.name, fc.args)

# Send the response back to Gemini

await self.session.send_tool_response(

function_responses=[{

“id”: fc.id,

“name”: fc.name,

“response”: {“result”: result}

        }\]

    )

What I suspect: Since response.data (audio) and response.tool_call can arrive in the same turn, the audio starts playing while the tool is being processed. When send_tool_response is called, the model seems to re-generate the response from the beginning of that turn, incorporating the new tool data, but without realizing it has already sent audio for that turn.

Do you have a suggestion on how to synchronize this better?

Best regards, Marcelo