agentscope-ai/agentscope · error · RuntimeError
CosyVoice TTS synthesis timed out after 30s
Error message
CosyVoice TTS synthesis timed out after 30s
What it means
CosyVoice real-time TTS synthesis over a WebSocket did not produce audio within a 30-second timeout. The library raises this after exhausting retry attempts (with exponential backoff and reconnection) because the websocket send/ack or audio stream stalled. It wraps the dashscope CosyVoice websocket API in agentscope's _cosyvoice_model.
Source
Thrown at src/agentscope/tts/_dashscope/_cosyvoice_model.py:320
self._synthesizer.streaming_complete()
finished = await asyncio.to_thread(
self._callback.finish_event.wait,
30,
)
if not finished:
logger.warning(
"CosyVoice TTS: timed out waiting for synthesis "
"completion (30s)",
)
if attempt < self.max_retries - 1:
await asyncio.sleep(delay)
await self._reconnect()
unsent = full_text
delay *= 2
continue
raise RuntimeError(
"CosyVoice TTS synthesis timed out after 30s",
)
if full_text and not self._callback.has_audio_data():
if attempt < self.max_retries - 1:
logger.warning(
"CosyVoice TTS: no audio received, retrying "
"(%d/%d) in %.1fs...",
attempt + 1,
self.max_retries,
delay,
)
await asyncio.sleep(delay)
await self._reconnect()
unsent = full_text
delay *= 2
continue
raise RuntimeError(View on GitHub (pinned to e90f1c7592)
Solutions
- Verify the DASHSCOPE_API_KEY is valid and has quota (test with a simple dashscope REST call).
- Check network/proxy allows outbound wss:// dashscope websocket endpoints.
- Split very long text into smaller chunks before calling synthesize().
- Increase max_retries / tune timeout if the environment is known to be slow.
- Retry the whole synthesize() call at the application level with backoff.
Example fix
# before
audio = await tts.synthesize(long_text)
# after
for chunk in chunks_of(long_text, 500):
audio = await tts.synthesize(chunk)
# plus: ensure os.environ["DASHSCOPE_API_KEY"] is set and valid Defensive patterns
Strategy: retry
Validate before calling
import os
assert os.environ.get("DASHSCOPE_API_KEY"), "set DASHSCOPE_API_KEY" Try / catch
try:
audio = await tts.synthesize(text)
except RuntimeError as e:
if "timed out" in str(e):
audio = await tts.synthesize(text[:500]) # shrink and retry once
else:
raise Prevention
- Set and verify DASHSCOPE_API_KEY before creating the model.
- Chunk long input texts (<500 chars per call).
- Ensure outbound wss:// traffic is allowed by proxies/firewalls.
When it happens
Trigger: Calling synthesize() on a DashScopeCosyVoiceTTSModel (realtime path) where the websocket stops delivering audio: network stall, expired/invalid DASHSCOPE_API_KEY causing silent server-side close, very long input text, or a blocked/proxied websocket connection. Raised inside _synthesize_realtime only when attempt == max_retries - 1 after timeout.
Common situations: Invalid or quota-exhausted DashScope API key, corporate proxy/firewall blocking wss:// connections, sending extremely long texts in one push, intermittent network drops on macOS sleep/wake, or the CosyVoice service being degraded.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- CosyVoice TTS synthesis failed: no audio after {self.max_ret
- TTS model is not connected. Call `connect()` first.
- TTS synthesis failed: no audio after {self.max_retries} atte
- TTS model is not connected. Call `connect()` first.
- Feishu channel requires 'lark-oapi' (pip install lark-oapi).
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/7f4e4b3dcd379d88.
Report an issue: GitHub.