odysseus-dev/odysseus · error · HTTPException
Synthesis failed: {str(e)}
Error message
Synthesis failed: {str(e)} What it means
HTTP 500 from POST /api/tts/synthesize when any unexpected exception escapes the try block (HTTPExceptions are re-raised untouched by 'except HTTPException: raise'). The catch-all logs with exc_info and returns detail {'message': f'Synthesis failed: {str(e)}'}, embedding the underlying exception text in the response.
Source
Thrown at routes/tts_routes.py:72
detail={"message": "Synthesis failed"}
)
# Detect format from magic bytes (MP3: ID3 tag or sync word ff e0+)
is_mp3 = audio_data[:3] == b'ID3' or (len(audio_data) >= 2 and audio_data[0] == 0xff and (audio_data[1] & 0xe0) == 0xe0)
mime = "audio/mpeg" if is_mp3 else "audio/wav"
return Response(
content=audio_data,
media_type=mime,
headers={
"Content-Disposition": "inline; filename=speech.mp3" if "mpeg" in mime else "inline; filename=speech.wav"
}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Synthesis error: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail={"message": f"Synthesis failed: {str(e)}"}
)
@router.post("/clear-cache")
async def clear_tts_cache():
"""Clear TTS cache"""
try:
tts_service.clear_cache()
return {"success": True, "message": "Cache cleared"}
except Exception as e:
logger.error(f"Failed to clear cache: {e}")
raise HTTPException(status_code=500, detail=str(e))
return router
View on GitHub (pinned to f9235ebbf1)
Solutions
- Read the server log line 'Synthesis error: ...' with stack trace — the HTTP detail is only the summary
- Fix the underlying cause (network reachability, provider auth, text encoding)
- Add request timeouts/retries around the provider call inside the service
- Return a generic message instead of str(e) if the API is exposed to untrusted clients
Example fix
# before
raise HTTPException(status_code=500, detail={"message": f"Synthesis failed: {str(e)}"})
# after
logger.exception("Synthesis error")
raise HTTPException(status_code=502, detail={"message": "TTS provider error"}) Defensive patterns
Strategy: try-catch
Validate before calling
if (!ttsServiceAvailable()) throw new Error('TTS off'); // avoids most 500 paths Try / catch
try { await synthesize(text); } catch (e) { if (is5xx(e)) showGenericTtsError(e); /* never surface str(e) verbatim */ } Prevention
- The server-side stack trace is authoritative — the client sees only the summary
- Add a client-side timeout plus a single retry with backoff
- Report the server log excerpt when filing issues
When it happens
Trigger: Any exception in synthesize_to_base64/synthesize other than the empty-return case: network timeout to the TTS provider, encoding error on exotic input text, AttributeError from a half-initialized backend.
Common situations: Provider timeout or DNS failure at synthesis time; Unicode text that breaks the engine's encoder; str(e) exposing internal details (URLs, paths) to API clients.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/31652182108ce7c8.
Report an issue: GitHub.