HKUDS/DeepTutor · error · VoiceProviderError
{exc}; original /audio/speech error: {original_error}
Error message
{exc}; original /audio/speech error: {original_error} What it means
In the OpenRouter fallback, the chat/completions endpoint itself returned HTTP >= 400 (converted by _raise_for_provider into VoiceProviderHTTPError). The adapter re-wraps it as VoiceProviderError chaining both the fallback failure and the original /audio/speech error so the developer sees why the fallback was attempted at all.
Source
Thrown at deeptutor/services/voice/adapters/openai_compat.py:237
"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_type
@staticmethodView on GitHub (pinned to 3e82f13042)
Solutions
- Read both halves of the message — the original /audio/speech error often identifies the root cause (e.g. model lacks audio)
- Switch to an audio-capable OpenRouter model
- Check API key validity and account credits (401/402)
- If the original error is 404, fix base_url before debugging the fallback
Defensive patterns
Strategy: try-catch
Try / catch
try:
audio, ct = await adapter.synthesize(text, config)
except VoiceProviderError as exc:
log.error("Both /audio/speech and chat fallback failed: %s", exc)
notify_user_voice_unavailable()
raise Prevention
- Treat the chained message as one incident: fix the original /audio/speech error
- Verify model audio support and account credits before enabling the fallback
When it happens
Trigger: /audio/speech failed with an HTTP error AND the subsequent chat/completions audio request also returned 4xx/5xx (bad model, auth, quota, unsupported audio modulation).
Common situations: Model lacks audio output support on both endpoints, key/credit problems, or audio-preview models not enabled for the account. The dual message is the key diagnostic: both endpoints rejected the request.
Related errors
- {exc}{hint}
- No endpoint URL configured for this provider.
- TTS request error: {detail}
- OpenRouter chat audio returned no audio chunks; original /au
- OpenRouter chat audio returned invalid base64.
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/2636500ff51cc415.
Report an issue: GitHub.