{"record":{"id":"53b26128e72a1a6f","repo":"odysseus-dev/odysseus","slug":"str-e-53b261","errorCode":null,"errorMessage":"str(e)","messagePattern":"str\\(e\\)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"routes/tts_routes.py","lineNumber":28,"sourceCode":"\nlogger = logging.getLogger(__name__)\n\nclass TTSRequest(BaseModel):\n    text: str\n    format: str = \"audio\"  # \"audio\" or \"base64\"\n\ndef 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                    )","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/tts_routes.py#L10-L46","documentation":"HTTP 500 from GET /api/tts/stats raised when tts_service.get_stats() throws any exception; the handler logs it and re-raises with detail=str(e), forwarding the raw internal message to the client. Typical underlying causes are an uninitialized TTS backend or corrupt cache statistics.","triggerScenarios":"GET /api/tts/stats when the TTS service failed during startup (missing edge-tts/pyttsx3 dependency, no network to the TTS provider) and get_stats() dereferences an uninitialized backend.","commonSituations":"Deployed without the TTS extras installed; TTS provider endpoint unreachable so partial init left stats in a broken state; str(e) in the response leaking internal paths/exception text to clients.","solutions":["Check the server logs for the original 'Failed to get TTS stats' line to identify the real exception","Verify the TTS backend dependency is installed and tts_service.available is true","If stats are only broken while the backend is down, fix availability first — this 500 is a symptom","Patch the route to return a generic 500 message instead of str(e) to avoid detail leakage"],"exampleFix":"# before\nraise HTTPException(status_code=500, detail=str(e))\n# after\nraise HTTPException(status_code=500, detail=\"TTS stats unavailable\")","handlingStrategy":"try-catch","validationCode":"const stats = await getTtsStats();\nif (!stats.available) { disableTtsUi(); }","typeGuard":null,"tryCatchPattern":"try { const s = await getTtsStats(); } catch (e) { /* 500: log, disable TTS UI, do not retry-loop */ }","preventionTips":["Check /stats once at UI boot and cache availability","Do not expose str(e) content to end users — log it and show a generic message"],"tags":["http","tts","fastapi","error-handling"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}