{"record":{"id":"7f4e4b3dcd379d88","repo":"agentscope-ai/agentscope","slug":"cosyvoice-tts-synthesis-timed-out-after-30s","errorCode":null,"errorMessage":"CosyVoice TTS synthesis timed out after 30s","messagePattern":"CosyVoice TTS synthesis timed out after 30s","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/agentscope/tts/_dashscope/_cosyvoice_model.py","lineNumber":320,"sourceCode":"                    self._synthesizer.streaming_complete()\n\n                    finished = await asyncio.to_thread(\n                        self._callback.finish_event.wait,\n                        30,\n                    )\n\n                    if not finished:\n                        logger.warning(\n                            \"CosyVoice TTS: timed out waiting for synthesis \"\n                            \"completion (30s)\",\n                        )\n                        if attempt < self.max_retries - 1:\n                            await asyncio.sleep(delay)\n                            await self._reconnect()\n                            unsent = full_text\n                            delay *= 2\n                            continue\n                        raise RuntimeError(\n                            \"CosyVoice TTS synthesis timed out after 30s\",\n                        )\n\n                    if full_text and not self._callback.has_audio_data():\n                        if attempt < self.max_retries - 1:\n                            logger.warning(\n                                \"CosyVoice TTS: no audio received, retrying \"\n                                \"(%d/%d) in %.1fs...\",\n                                attempt + 1,\n                                self.max_retries,\n                                delay,\n                            )\n                            await asyncio.sleep(delay)\n                            await self._reconnect()\n                            unsent = full_text\n                            delay *= 2\n                            continue\n                        raise RuntimeError(","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/tts/_dashscope/_cosyvoice_model.py#L302-L338","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\naudio = await tts.synthesize(long_text)\n\n# after\nfor chunk in chunks_of(long_text, 500):\n    audio = await tts.synthesize(chunk)\n# plus: ensure os.environ[\"DASHSCOPE_API_KEY\"] is set and valid","handlingStrategy":"retry","validationCode":"import os\nassert os.environ.get(\"DASHSCOPE_API_KEY\"), \"set DASHSCOPE_API_KEY\"","typeGuard":null,"tryCatchPattern":"try:\n    audio = await tts.synthesize(text)\nexcept RuntimeError as e:\n    if \"timed out\" in str(e):\n        audio = await tts.synthesize(text[:500])  # shrink and retry once\n    else:\n        raise","preventionTips":["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."],"tags":["tts","dashscope","cosyvoice","websocket","timeout","asyncio"],"backgroundTag":"websocket-timeout","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}