HKUDS/DeepTutor · error · VoiceProviderError

OpenRouter chat audio error: {message}

Error message

OpenRouter chat audio error: {message}

What it means

_collect_audio_line parses each SSE line from the OpenRouter chat stream; if the decoded JSON chunk contains an "error" object, it extracts message/code and raises VoiceProviderError("OpenRouter chat audio error: {message}"). This surfaces mid-stream errors that arrive with HTTP 200.

Source

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

    @staticmethod
    def _collect_audio_line(line: str, audio_chunks: list[str]) -> None:
        if not line:
            return
        raw = line.strip()
        if not raw.startswith("data:"):
            return
        data = raw[len("data:") :].strip()
        if not data or data == "[DONE]":
            return
        try:
            chunk = json.loads(data)
        except json.JSONDecodeError:
            logger.debug("Ignoring malformed OpenRouter SSE line: %s", data[:160])
            return
        error = chunk.get("error")
        if isinstance(error, dict):
            message = error.get("message") or error.get("code") or "unknown error"
            raise VoiceProviderError(f"OpenRouter chat audio error: {message}")
        choices = chunk.get("choices")
        if not isinstance(choices, list):
            return
        for choice in choices:
            if not isinstance(choice, dict):
                continue
            delta = choice.get("delta") or {}
            if not isinstance(delta, dict):
                continue
            audio = delta.get("audio") or {}
            if isinstance(audio, dict) and isinstance(audio.get("data"), str):
                audio_chunks.append(audio["data"])


class OpenAICompatSTTAdapter(BaseSTTAdapter):
    """POST ``{base}/audio/transcriptions``.

    Multipart ``file`` upload by default; OpenRouter uses a base64-JSON body

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Act on the embedded message: top up credits (402-style), fix the model slug, or adjust content that triggered moderation
  2. Retry once for transient credit/auth propagation delays
  3. Verify the model exists and supports audio on OpenRouter's model listing
  4. If errors persist, disable the chat fallback and use a native TTS provider
Defensive patterns

Strategy: try-catch

Try / catch

try:
    audio, ct = await adapter.synthesize(text, config)
except VoiceProviderError as exc:
    if "chat audio error" in str(exc):
        log.error("OpenRouter stream error: %s", exc)  # credits/model/moderation
    raise

Prevention

When it happens

Trigger: The chat/completions stream starts with HTTP 200 but emits an error event — e.g. invalid model, insufficient credits, or content-policy rejection delivered as an SSE error payload.

Common situations: OpenRouter credit exhaustion mid-request, deprecated/renamed model slug, or moderation blocks — all delivered as in-stream error objects instead of HTTP status codes.

Related errors


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