{"record":{"id":"e592b5c55c63c53e","repo":"HKUDS/DeepTutor","slug":"no-endpoint-url-configured-for-stt","errorCode":null,"errorMessage":"No endpoint URL configured for STT.","messagePattern":"No endpoint URL configured for STT\\.","errorType":"exception","errorClass":"VoiceProviderError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/voice/adapters/openai_compat.py","lineNumber":304,"sourceCode":"\n\nclass OpenAICompatSTTAdapter(BaseSTTAdapter):\n    \"\"\"POST ``{base}/audio/transcriptions``.\n\n    Multipart ``file`` upload by default; OpenRouter uses a base64-JSON body\n    (``request_style == \"base64_json\"``) sharing the same path.\n    \"\"\"\n\n    async def transcribe(\n        self,\n        audio: bytes,\n        config: STTConfig,\n        *,\n        filename: str = \"audio.webm\",\n        content_type: str = \"application/octet-stream\",\n    ) -> str:\n        if not config.base_url:\n            raise VoiceProviderError(\"No endpoint URL configured for STT.\")\n        if not audio:\n            raise VoiceProviderError(\"No audio data to transcribe.\")\n        url = join_audio_path(config.base_url, \"audio/transcriptions\")\n        auth = build_auth_headers(config.auth_style, config.api_key)\n\n        try:\n            async with httpx.AsyncClient(timeout=config.request_timeout) as client:\n                if config.request_style == STT_BASE64_JSON:\n                    resp = await self._post_base64(client, url, auth, audio, filename, config)\n                else:\n                    resp = await self._post_multipart(\n                        client, url, auth, audio, filename, content_type, config\n                    )\n        except httpx.HTTPError as exc:\n            raise VoiceProviderError(f\"STT request error: {exc}\") from exc\n        _raise_for_provider(resp, \"Transcription\")\n        return self._parse_text(resp)\n","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/voice/adapters/openai_compat.py#L286-L322","documentation":"OpenAICompatSTTAdapter.transcribe requires config.base_url before it can build the {base}/audio/transcriptions URL; an empty/None base_url raises VoiceProviderError immediately. Configuration guard for the speech-to-text path.","triggerScenarios":"Calling transcribe(audio, config) with STTConfig.base_url empty — e.g. STT provider settings only contain an API key, or the env override cleared the endpoint.","commonSituations":"Assuming a default OpenAI endpoint exists without configuring it, settings JSON missing the stt.base_url field after an upgrade, or copy-pasting a key-only config from another tool.","solutions":["Set base_url on the STTConfig / voice settings (e.g. https://api.openai.com/v1)","Check data/user/settings/*.json and env overrides for an empty STT endpoint","Validate voice provider config at startup"],"exampleFix":"// before\ncfg = STTConfig(api_key=key)\n// after\ncfg = STTConfig(base_url=\"https://api.openai.com/v1\", api_key=key)","handlingStrategy":"validation","validationCode":"if not (stt_config.base_url or \"\").strip():\n    raise ValueError(\"STT base_url must be configured\")","typeGuard":null,"tryCatchPattern":"try:\n    text = await stt.transcribe(audio, stt_config)\nexcept VoiceProviderError as exc:\n    if \"No endpoint URL configured for STT\" in str(exc):\n        alert_admin_missing_stt_endpoint()  # config error, no retry","preventionTips":["Require base_url in STT settings schema","Validate voice config on startup"],"tags":["voice","stt","missing-config","endpoint"],"backgroundTag":"missing-base-url","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}