{"record":{"id":"ad932a60c966a47f","repo":"odysseus-dev/odysseus","slug":"tts-service-not-available","errorCode":null,"errorMessage":"TTS service not available","messagePattern":"TTS service not available","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"warning","filePath":"routes/tts_routes.py","lineNumber":35,"sourceCode":"def setup_tts_routes(tts_service):\n    \"\"\"Setup TTS routes with the provided TTS service\"\"\"\n    router = APIRouter(prefix=\"/api/tts\", tags=[\"tts\"])\n\n    @router.get(\"/stats\")\n    async def get_tts_stats():\n        \"\"\"Get TTS service statistics\"\"\"\n        try:\n            return tts_service.get_stats()\n        except Exception as e:\n            logger.error(f\"Failed to get TTS stats: {e}\")\n            raise HTTPException(status_code=500, detail=str(e))\n\n    @router.post(\"/synthesize\")\n    async def synthesize_speech(request: TTSRequest):\n        \"\"\"Synthesize speech from text\"\"\"\n        try:\n            if not tts_service.available:\n                raise HTTPException(\n                    status_code=503,\n                    detail={\"message\": \"TTS service not available\"}\n                )\n            \n            if request.format == \"base64\":\n                audio_b64 = tts_service.synthesize_to_base64(request.text)\n                if not audio_b64:\n                    raise HTTPException(\n                        status_code=500,\n                        detail={\"message\": \"Synthesis failed\"}\n                    )\n                return {\"audio\": audio_b64}\n            \n            else:  # audio format\n                audio_data = tts_service.synthesize(request.text)\n                if not audio_data:\n                    raise HTTPException(\n                        status_code=500,","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/tts_routes.py#L17-L53","documentation":"HTTP 503 from POST /api/tts/synthesize when tts_service.available is false — the service detected at startup that no usable TTS backend exists. This capability flag is checked before any synthesis attempt, so the request never reaches the engine.","triggerScenarios":"POST /api/tts/synthesize on an instance whose TTS backend failed init: dependency not installed, provider unreachable at startup, or the feature disabled in config.","commonSituations":"Container/image built without TTS dependencies; offline environment where the cloud TTS engine could not be reached during init; feature intentionally disabled so available stays False.","solutions":["Install/enable the TTS backend the service expects (e.g. edge-tts) and restart the service","Check TTS configuration (endpoint, voice list) and network reachability, then restart so availability is re-evaluated","Frontend should treat 503 as 'feature off' and hide/disable the speak button","Verify via GET /api/tts/stats whether the service reports itself available before retrying synthesis"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const stats = await getTtsStats();\nif (!stats?.available) throw new Error('TTS disabled on this server');","typeGuard":"function ttsAvailable(s: unknown): s is { available: true } {\n  return !!s && (s as any).available === true;\n}","tryCatchPattern":"if (resp.status === 503) { hideSpeakButtons(); return; } // permanent condition, do not retry","preventionTips":["Query /api/tts/stats before showing TTS controls","Treat 503 as configuration, not transient — retrying will not help"],"tags":["http","tts","availability","fastapi"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}