HKUDS/DeepTutor · error · VoiceProviderError

Transcription response had no `text` field.

Error message

Transcription response had no `text` field.

What it means

_parse_text inspects the transcription response: it expects a JSON body with a "text" field (or, as a fallback, a choices[0].message.content string for chat-style endpoints). If neither is present, VoiceProviderError is raised. Note that response_format=text (bare string body) skips this check.

Source

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

        headers = {"Content-Type": "application/json", **auth, **(config.extra_headers or {})}
        return await client.post(url, headers=headers, json=body)

    @staticmethod
    def _parse_text(resp: httpx.Response) -> str:
        content_type = resp.headers.get("content-type", "")
        if "json" in content_type:
            data = resp.json()
            if isinstance(data, dict):
                text = data.get("text")
                if isinstance(text, str):
                    return text.strip()
                # OpenRouter/chat-style fallback.
                choices = data.get("choices")
                if isinstance(choices, list) and choices:
                    message = (choices[0] or {}).get("message") or {}
                    if isinstance(message.get("content"), str):
                        return message["content"].strip()
            raise VoiceProviderError("Transcription response had no `text` field.")
        # response_format=text returns a bare string.
        return (resp.text or "").strip()


__all__ = ["OpenAICompatTTSAdapter", "OpenRouterTTSAdapter", "OpenAICompatSTTAdapter"]

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Log/inspect resp text to see the actual schema returned
  2. If the gateway uses a different field name, switch to an OpenAI-compatible endpoint or wrap it with an adapter that maps the field
  3. Ensure response_format is set so the provider returns the expected shape
  4. Verify the URL actually points to a transcriptions endpoint, not a captive/login page
Defensive patterns

Strategy: try-catch

Try / catch

try:
    text = await stt.transcribe(audio, stt_config)
except VoiceProviderError as exc:
    if "no `text` field" in str(exc):
        log.error("Unexpected STT response schema — check gateway compatibility")
    raise

Prevention

When it happens

Trigger: The provider returned 200 with JSON lacking "text" — e.g. an error payload, a different schema (some gateways return {transcript: ...}), or an HTML login/error page parsed as JSON.

Common situations: Non-OpenAI-compatible STT gateway whose response schema differs, a proxy returning an HTML error page with 200, or a chat-completions endpoint used for STT whose reply has empty content.

Related errors


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