HKUDS/DeepTutor · error · VoiceProviderError

TTS request error: {exc}

Error message

TTS request error: {exc}

What it means

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.

Source

Thrown at deeptutor/services/voice/adapters/openai_compat.py:147

        }
        if config.voice:
            payload["voice"] = config.voice
        if config.speed is not None:
            payload["speed"] = config.speed

        logger.debug(
            "TTS synthesize url=%s model=%s voice=%s fmt=%s chars=%d",
            url,
            config.model,
            config.voice,
            response_format,
            len(text),
        )
        try:
            async with httpx.AsyncClient(timeout=config.request_timeout) as client:
                resp = await client.post(url, headers=headers, json=payload)
        except httpx.HTTPError as exc:
            raise VoiceProviderError(f"TTS request error: {exc}") from exc
        try:
            _raise_for_provider(resp, "TTS synthesis")
        except VoiceProviderHTTPError as exc:
            hint = _openrouter_tts_hint(config)
            if hint:
                raise VoiceProviderError(f"{exc}{hint}") from exc
            raise
        audio = resp.content
        if not audio:
            raise VoiceProviderError("TTS provider returned empty audio.")
        content_type = resp.headers.get("content-type") or _FORMAT_CONTENT_TYPES.get(
            response_format, "application/octet-stream"
        )
        # Some gateways return JSON content-type with audio; trust the format map.
        if "json" in content_type:
            content_type = _FORMAT_CONTENT_TYPES.get(response_format, "audio/mpeg")
        return audio, content_type

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Check the embedded httpx error: connect errors mean wrong host/DNS, read timeouts mean increase request_timeout
  2. Verify network/proxy egress to the provider base_url with curl
  3. Increase TTSConfig.request_timeout or shorten/split the input text for long syntheses
  4. If TLS-related, fix the certificate trust of the client environment

Example fix

// before
cfg = TTSConfig(base_url=url, api_key=key, request_timeout=5)
// after
cfg = TTSConfig(base_url=url, api_key=key, request_timeout=60)
Defensive patterns

Strategy: retry

Validate before calling

import httpx
assert (config.base_url or "").startswith(("http://", "https://")), "base_url must be an absolute URL"

Try / catch

for attempt in range(3):
    try:
        return await adapter.synthesize(text, config)
    except VoiceProviderError as exc:
        if "TTS request error" not in str(exc) or attempt == 2:
            raise
        await asyncio.sleep(2 ** attempt)

Prevention

When it happens

Trigger: Provider host unreachable, DNS failure, TLS certificate error, or request_timeout exceeded during the TTS POST. Any non-HTTP-status httpx error triggers this.

Common situations: 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.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/77f70058538c6747. Report an issue: GitHub.