{"record":{"id":"77f70058538c6747","repo":"HKUDS/DeepTutor","slug":"tts-request-error-exc","errorCode":null,"errorMessage":"TTS request error: {exc}","messagePattern":"TTS request error: (.+?)","errorType":"exception","errorClass":"VoiceProviderError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/voice/adapters/openai_compat.py","lineNumber":147,"sourceCode":"        }\n        if config.voice:\n            payload[\"voice\"] = config.voice\n        if config.speed is not None:\n            payload[\"speed\"] = config.speed\n\n        logger.debug(\n            \"TTS synthesize url=%s model=%s voice=%s fmt=%s chars=%d\",\n            url,\n            config.model,\n            config.voice,\n            response_format,\n            len(text),\n        )\n        try:\n            async with httpx.AsyncClient(timeout=config.request_timeout) as client:\n                resp = await client.post(url, headers=headers, json=payload)\n        except httpx.HTTPError as exc:\n            raise VoiceProviderError(f\"TTS request error: {exc}\") from exc\n        try:\n            _raise_for_provider(resp, \"TTS synthesis\")\n        except VoiceProviderHTTPError as exc:\n            hint = _openrouter_tts_hint(config)\n            if hint:\n                raise VoiceProviderError(f\"{exc}{hint}\") from exc\n            raise\n        audio = resp.content\n        if not audio:\n            raise VoiceProviderError(\"TTS provider returned empty audio.\")\n        content_type = resp.headers.get(\"content-type\") or _FORMAT_CONTENT_TYPES.get(\n            response_format, \"application/octet-stream\"\n        )\n        # Some gateways return JSON content-type with audio; trust the format map.\n        if \"json\" in content_type:\n            content_type = _FORMAT_CONTENT_TYPES.get(response_format, \"audio/mpeg\")\n        return audio, content_type\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/voice/adapters/openai_compat.py#L129-L165","documentation":"While synthesizing speech, the httpx AsyncClient POST to the provider's /audio/speech endpoint raised an httpx.HTTPError (connection failure, timeout, DNS, TLS). The adapter wraps it in VoiceProviderError with the underlying exception text so transport-level failures are visible.","triggerScenarios":"Provider host unreachable, DNS failure, TLS certificate error, or request_timeout exceeded during the TTS POST. Any non-HTTP-status httpx error triggers this.","commonSituations":"Wrong/typo'd base_url domain, firewall or proxy blocking egress, self-signed cert on a self-hosted gateway, or a very low request_timeout against a slow TTS model.","solutions":["Check the embedded httpx error: connect errors mean wrong host/DNS, read timeouts mean increase request_timeout","Verify network/proxy egress to the provider base_url with curl","Increase TTSConfig.request_timeout or shorten/split the input text for long syntheses","If TLS-related, fix the certificate trust of the client environment"],"exampleFix":"// before\ncfg = TTSConfig(base_url=url, api_key=key, request_timeout=5)\n// after\ncfg = TTSConfig(base_url=url, api_key=key, request_timeout=60)","handlingStrategy":"retry","validationCode":"import httpx\nassert (config.base_url or \"\").startswith((\"http://\", \"https://\")), \"base_url must be an absolute URL\"","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        return await adapter.synthesize(text, config)\n    except VoiceProviderError as exc:\n        if \"TTS request error\" not in str(exc) or attempt == 2:\n            raise\n        await asyncio.sleep(2 ** attempt)","preventionTips":["Set request_timeout appropriate to model latency (30s+)","Verify DNS/proxy egress to the provider host before enabling voice","Retry with exponential backoff only for transport errors, never for config errors"],"tags":["voice","tts","network","timeout","httpx"],"backgroundTag":"http-request-failed","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}