HKUDS/DeepTutor · error · VoiceProviderError
TTS request error: {detail}
Error message
TTS request error: {detail} What it means
During the OpenRouter chat/completions audio fallback, the httpx POST failed at the transport level (httpx.HTTPError) and the adapter wraps it as VoiceProviderError("TTS request error: {detail}"). Same family as the main-path transport error but on the fallback endpoint.
Source
Thrown at deeptutor/services/voice/adapters/openai_compat.py:235
logger.debug(
"OpenRouter chat-audio synthesize url=%s model=%s voice=%s fmt=%s chars=%d",
url,
config.model,
config.voice,
audio_format,
len(text),
)
audio_chunks: list[str] = []
try:
async with httpx.AsyncClient(timeout=config.request_timeout) as client:
resp = await client.post(url, headers=headers, json=payload)
_raise_for_provider(resp, "OpenRouter chat audio synthesis")
for line in (resp.text or "").splitlines():
self._collect_audio_line(line, audio_chunks)
except httpx.HTTPError as exc:
detail = str(exc) or exc.__class__.__name__
raise VoiceProviderError(f"TTS request error: {detail}") from exc
except VoiceProviderHTTPError as exc:
raise VoiceProviderError(
f"{exc}; original /audio/speech error: {original_error}"
) from exc
if not audio_chunks:
raise VoiceProviderError(
"OpenRouter chat audio returned no audio chunks; "
f"original /audio/speech error: {original_error}"
)
try:
audio = base64.b64decode("".join(audio_chunks))
except binascii.Error as exc:
raise VoiceProviderError("OpenRouter chat audio returned invalid base64.") from exc
if not audio:
raise VoiceProviderError("OpenRouter chat audio returned empty audio.")
content_type = _FORMAT_CONTENT_TYPES.get(audio_format, "application/octet-stream")
return audio, content_typeView on GitHub (pinned to 3e82f13042)
Solutions
- Increase request_timeout — chat audio generation is slower than /audio/speech
- Retry the whole synthesis; if /audio/speech fails persistently at HTTP level, fix that first (see the original error chain)
- Verify egress to the chat/completions endpoint
- Consider disabling the OpenRouter fallback and using a native TTS provider
Example fix
// before cfg = TTSConfig(request_timeout=10) // after cfg = TTSConfig(request_timeout=120)
Defensive patterns
Strategy: retry
Try / catch
try:
return await adapter.synthesize(text, config)
except VoiceProviderError as exc:
if "TTS request error" in str(exc):
return await asyncio.wait_for(adapter.synthesize(text, config), timeout=180)
raise Prevention
- Chat-audio generation is slow — budget generous timeouts
- Keep a native TTS provider as fallback when OpenRouter is flaky
When it happens
Trigger: Network/DNS/TLS/timeout failure specifically while POSTing to {base_url}/chat/completions in the fallback, after /audio/speech already failed with an HTTP error.
Common situations: Transient network drop between the two requests, request_timeout too small for chat-with-audio generation (which is slower than direct TTS), or proxy interference on streaming responses.
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
- TTS request error: {exc}
- No endpoint URL configured for this provider.
- {exc}{hint}
- {exc}; original /audio/speech error: {original_error}
- OpenRouter chat audio returned no audio chunks; original /au
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/39e39532de221bb9.
Report an issue: GitHub.