-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Describe the Bug:
When using the Multimodal Live API with google-adk, the WebSocket connection frequently terminates with a google.genai.errors.APIError: 1000 None. error. This occurs during the run_live loop, specifically when the ADK is awaiting a message from the Gemini model. The trace suggests the error originates deep within the google-genai SDK's _receive method, indicating a clean but unexpected WebSocket closure by the server/backend without a specific error reason.
Steps to Reproduce:
Initialize an ADK LlmAgent using the gemini-live-2.5-flash-native-audio model on Vertex AI.
Deploy the application to Google Cloud Run (or run locally with high-latency streaming).
Establish a bidirectional session using agent.run_live().
Engage in a multi-turn conversation or wait for a model response.
Observe the connection drop with the 1000 None traceback.
Expected Behavior:
The WebSocket connection should remain persistent for the duration of the session, handling bidirectional audio/text streams without abrupt closure.
Observed Behavior:
The connection closes unexpectedly with status code 1000 (Normal Closure) but no reason string (None), causing the ADK runner to crash.
Plaintext
google.genai.errors.APIError: 1000 None.
File "/app/.venv/lib/python3.11/site-packages/google/genai/live.py", line 545, in _receive
errors.APIError.raise_error(code, reason, None)
Environment Details:
ADK Library Version (pip show google-adk): 1.25.1 (or latest as of Feb 2026)
Desktop OS: Linux (Containerized on Cloud Run)
Python Version (python -V): 3.11.x
Model Information:
Are you using LiteLLM: No
Which model is being used: gemini-live-2.5-flash-native-audio (Vertex AI)
🟡 Optional Information
Regression:
Unknown. However, I have have noted higher stability on the gemini-live-2.5-flash-native-audio endpoint via the Gemini API compared to the Vertex AI endpoint.
Logs:
Traceback (most recent call last):
File "/app/.venv/lib/python3.11/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 199, in run_live
async for event in agen:
File "/app/.venv/lib/python3.11/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 371, in _receive_from_model
async for llm_response in agen:
File "/app/.venv/lib/python3.11/site-packages/google/adk/models/gemini_llm_connection.py", line 172, in receive
async for message in agen:
File "/app/.venv/lib/python3.11/site-packages/google/genai/live.py", line 454, in receive
while result := await self._receive():
File "/app/.venv/lib/python3.11/site-packages/google/genai/live.py", line 545, in _receive
errors.APIError.raise_error(code, reason, None)
google.genai.errors.APIError: 1000 None.
Additional Context:
The issue persists even when Cloud Run timeouts are increased to 3600s and HTTP/2 is enabled. It appears to be an application-level or API-level disconnect rather than a network timeout.
Minimal Reproduction Code:
Python
import asyncio
import os
from fastapi import FastAPI, WebSocket
from google.adk.agents.live_request_queue import LiveRequestQueue
from google.adk.agents.run_config import RunConfig, StreamingMode
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.memory import InMemoryMemoryService
from google.adk.agents import LlmAgent
from google.genai import types
1. Minimal Agent Setup
Replace with your specific instructions/tools if necessary
mock_agent = LlmAgent(
model="gemini-live-2.5-flash-native-audio",
instructions="You are a helpful tutor."
)
app = FastAPI()
session_service = InMemorySessionService()
memory_service = InMemoryMemoryService()
runner = Runner(
app_name="reproduction-app",
agent=mock_agent,
session_service=session_service,
memory_service=memory_service
)
@app.websocket("/ws/{user_id}/{session_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: str, session_id: str):
await websocket.accept()
# 2. Minimal RunConfig
run_config = RunConfig(
streaming_mode=StreamingMode.BIDI,
response_modalities=["AUDIO"],
input_audio_transcription=types.AudioTranscriptionConfig(),
output_audio_transcription=types.AudioTranscriptionConfig(),
speech_config=types.SpeechConfig(
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Zephyr")
)
)
)
live_request_queue = LiveRequestQueue()
# 3. Upstream: WebSocket -> Gemini
async def upstream_task():
try:
while True:
message = await websocket.receive()
if "bytes" in message:
audio_blob = types.Blob(mime_type="audio/pcm;rate=16000", data=message["bytes"])
live_request_queue.send_realtime(audio_blob)
except Exception:
live_request_queue.close()
# 4. Downstream: Gemini -> WebSocket (Where the 1000 None occurs)
async def downstream_task():
try:
async for event in runner.run_live(
user_id=user_id,
session_id=session_id,
live_request_queue=live_request_queue,
run_config=run_config,
):
await websocket.send_text(event.model_dump_json(exclude_none=True))
except Exception as e:
print(f"CRASH DETECTED: {e}")
await asyncio.gather(upstream_task(), downstream_task())
How often has this issue occurred?:
Always (100%+)