HKUDS/DeepTutor · error · VoiceProviderError
OpenRouter chat audio returned no audio chunks; original /au
Error message
OpenRouter chat audio returned no audio chunks; original /audio/speech error: {original_error} What it means
The OpenRouter chat/completions fallback completed with HTTP 200 and its SSE lines were scanned, but no audio chunks were collected (audio_chunks empty). The adapter raises VoiceProviderError including the original /audio/speech error for context. It means the model replied with text (or nothing parseable) instead of audio data.
Source
Thrown at deeptutor/services/voice/adapters/openai_compat.py:242
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
@staticmethod
def _collect_audio_line(line: str, audio_chunks: list[str]) -> None:
if not line:
return
raw = line.strip()
if not raw.startswith("data:"):View on GitHub (pinned to 3e82f13042)
Solutions
- Use an audio-capable model (e.g. *-audio-preview) on OpenRouter
- Check debug logs for "Ignoring malformed OpenRouter SSE line" — a format change would show there
- Test the same chat/completions request with curl including the audio output modulation to confirm the model emits audio
- Fall back to a native TTS provider for speech synthesis
Defensive patterns
Strategy: fallback
Try / catch
try:
audio, ct = await openrouter_adapter.synthesize(text, config)
except VoiceProviderError as exc:
if "no audio chunks" in str(exc):
return await native_tts.synthesize(text, native_config)
raise Prevention
- Use audio-preview models for the OpenRouter fallback
- Log which model produced no chunks to build a known-good list
When it happens
Trigger: The chat request succeeded but the model returned plain text content with no base64 audio payload — e.g. the model doesn't support the audio output modulation, or the prompt/modality flags weren't accepted.
Common situations: Using a non-audio model on OpenRouter with the fallback enabled; the gateway silently dropping the audio field; or an SSE format change that _collect_audio_line no longer recognizes.
Related errors
- OpenRouter chat audio returned empty audio.
- OpenRouter chat audio error: {message}
- No endpoint URL configured for this provider.
- {exc}{hint}
- TTS provider returned empty audio.
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/2be13acdd134891a.
Report an issue: GitHub.