HKUDS/DeepTutor · error · VoiceProviderError

{exc}{hint}

Error message

{exc}{hint}

What it means

After the provider returned an HTTP >= 400 for TTS synthesis, _raise_for_provider raised VoiceProviderHTTPError; if the config looks like OpenRouter (per _openrouter_tts_hint), the adapter re-raises as VoiceProviderError with an appended hint explaining OpenRouter's audio support. The message combines the provider error detail and the hint.

Source

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

        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


class OpenRouterTTSAdapter(BaseTTSAdapter):
    """OpenRouter TTS with fallback for streaming chat-audio models.

    OpenRouter documents both a dedicated ``/audio/speech`` endpoint for TTS
    models and audio output through ``/chat/completions`` for models that expose

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Read the appended hint — it usually says to use an audio-capable model or the chat fallback
  2. Switch the TTS model to one that supports /audio/speech on OpenRouter
  3. Verify the API key and account credits if the status is 401/402
  4. If the fallback should have run, ensure the adapter used is OpenRouterTTSAdapter so _synthesize_chat_audio is attempted

Example fix

// before
cfg = TTSConfig(model="gpt-4o-mini", base_url="https://openrouter.ai/api/v1")
// after
cfg = TTSConfig(model="openai/gpt-4o-audio-preview", base_url="https://openrouter.ai/api/v1")
Defensive patterns

Strategy: try-catch

Try / catch

try:
    audio, ct = await adapter.synthesize(text, config)
except VoiceProviderError as exc:
    if "OpenRouter" in str(exc):
        switch_to_native_tts_provider()  # fallback path
    raise

Prevention

When it happens

Trigger: OpenRouter-style TTS config gets a 4xx/5xx from /audio/speech (e.g. model does not support audio output) and the OpenRouter hint applies, producing this combined message.

Common situations: Using an OpenRouter model that lacks native audio/speech support; the hint typically tells you to rely on the chat/completions audio fallback or pick an audio-capable model.

Related errors


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