Skip to content

send_realtime_input(activity_end=...) in text-only Live session causes 1007 invalid payload and ignores client turn control #1720

Description

@sender001

When using the official Python Gemini / genai Live client with send_realtime_input in a text-only Live session, the model:

  1. Starts responding immediately after the first text input, ignoring the client-controlled end-of-turn.
  2. Returns WebSocket close code 1007 (invalid frame payload data) when an activity_end message is sent via send_realtime_input.

We are using send_realtime_input exactly as defined in the library:

  • send_realtime_input(activity_start=ActivityStart()) – to signal the start of user activity,
  • send_realtime_input(text="...") – to send user utterances as text (transcriptions from our own STT),
  • send_realtime_input(activity_end=ActivityEnd()) – to signal the end of user activity.

Only one argument is passed per call, in line with the method’s contract.

This behavior did not occur on the previous Gemini Live preview model, where the same client-side pattern (activity_start → multiple text messages → activity_end) worked as expected.

Our production flow depends on text-only, client-side turn-taking (we have our own STT and end-of-turn detector), so this currently blocks migration to gemini-live-2.5-flash.


Environment details

  • Programming language: Python 3.11
  • OS: macOS / Linux (reproduced on multiple environments)
  • Language runtime version: CPython 3.11.x
  • Package: official Python genai / Gemini Live client
    (using session.send_realtime_input(...) exactly as in the library code)
  • Model: google/gemini-live-2.5-flash
  • Input: text only (no audio/video sent)
  • Output: text only
  • Turn / activity detection: server-side VAD / automatic activity detection disabled; turn control is fully on the client

(Exact package and OS versions can be provided if needed.)


Steps to reproduce

  1. Create a Gemini Live session using the Python genai client in text-only mode:

    • model: google/gemini-live-2.5-flash,
    • response modalities: text,
    • no audio / video media sent,
    • server-side VAD / automatic activity detection disabled (client-side end-of-turn detection).
  2. When the user starts speaking (detected on the client side), call send_realtime_input with activity_start to signal the start of user activity.

  3. While the user is speaking, call send_realtime_input with text multiple times, passing consecutive transcribed fragments from STT.
    Each call uses exactly one argument: text="..." (no other fields set).

  4. When the client-side end-of-turn detector decides that the user has finished speaking, call send_realtime_input with activity_end to signal the end of the user turn.

  5. Observe the behavior:

    • The model starts generating text responses immediately after the first text message in step 3, before the activity_end event is sent.
    • When activity_end is eventually sent, the WebSocket connection is closed with:
      received 1007 (invalid frame payload data) Request contains an invalid argument.; then sent 1007 (invalid frame payload data) Request contains an invalid argument.

Throughout this sequence, all messages are sent via send_realtime_input with exactly one of the supported arguments (text, activity_start, or activity_end) per call.


Expected behavior

For a text-only Live session with server-side VAD disabled and using this pattern:

  • send_realtime_input(activity_start=...)
  • multiple send_realtime_input(text=...) calls while the user is speaking
  • send_realtime_input(activity_end=...) when the user is done

we expect that:

  • The model waits for the activity_end signal before starting to generate a response.
  • Sending activity_end via send_realtime_input(activity_end=...) is treated as a valid payload and does not close the WebSocket.
  • The response is only streamed after the client signals the end of the user turn.

This is how the same pattern behaved for us on the earlier Gemini Live preview model.


Actual behavior

With google/gemini-live-2.5-flash and the Python genai client:

  • As soon as the first send_realtime_input(text=...) call is made, the model immediately starts responding, even though activity_end has not been sent yet.
  • When send_realtime_input(activity_end=...) is called at the end of the user turn:
    • the WebSocket is closed, and
    • we receive 1007 (invalid frame payload data) – Request contains an invalid argument.

As a result:

  • client-controlled end-of-turn is effectively ignored, and
  • the activity_end event sent via send_realtime_input is treated as an invalid payload.

Additional context

  • We are migrating from the Gemini Live preview model (now being deprecated) to google/gemini-live-2.5-flash.
  • Our system already uses its own STT and end-of-turn detection, so we deliberately disable server-side VAD and depend on client-controlled turns.
  • The same activity_starttextactivity_end pattern previously worked reliably on the preview Live model.

If this is an intended change in behavior rather than a bug, guidance on the correct usage pattern for send_realtime_input with text-only, client-controlled turns (using activity_start / text / activity_end) would be very helpful.

Metadata

Metadata

Assignees

Labels

priority: p2Moderately-important priority. Fix may not be included in next release.status:awaiting user responsestatus:staletype: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions