odysseus-dev/odysseus · error · HTTPException
Synthesis failed
Error message
Synthesis failed
What it means
HTTP 500 from POST /api/tts/synthesize with format=='base64' when tts_service.synthesize_to_base64(text) returns an empty/falsy value. The call completed without raising but produced no audio, which the route treats as a hard failure rather than returning an empty clip.
Source
Thrown at routes/tts_routes.py:43
return tts_service.get_stats()
except Exception as e:
logger.error(f"Failed to get TTS stats: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/synthesize")
async def synthesize_speech(request: TTSRequest):
"""Synthesize speech from text"""
try:
if not tts_service.available:
raise HTTPException(
status_code=503,
detail={"message": "TTS service not available"}
)
if request.format == "base64":
audio_b64 = tts_service.synthesize_to_base64(request.text)
if not audio_b64:
raise HTTPException(
status_code=500,
detail={"message": "Synthesis failed"}
)
return {"audio": audio_b64}
else: # audio format
audio_data = tts_service.synthesize(request.text)
if not audio_data:
raise HTTPException(
status_code=500,
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,View on GitHub (pinned to f9235ebbf1)
Solutions
- Retry with plain alphanumeric text to confirm the engine works at all
- Check service logs for swallowed provider errors during synthesis; verify provider credentials/quota
- Clear the TTS cache (POST /api/tts/clear-cache) in case a corrupt empty entry is being served
- If reproducible, instrument tts_service.synthesize_to_base64 — the falsy return hides the real error
Defensive patterns
Strategy: retry
Validate before calling
if (!text.trim()) throw new Error('nothing to synthesize'); Try / catch
if (resp.status === 500 && body.message === 'Synthesis failed') { backoffRetry(2); } Prevention
- Strip emoji/zero-width characters from text before synthesis
- Fall back to plain text if rich text synthesis keeps failing
- Cache successful syntheses to avoid repeated engine load
When it happens
Trigger: POST /api/tts/synthesize with {"format":"base64"} where the engine silently produces nothing: text made only of characters the engine drops (emoji/whitespace), provider returned HTTP 200 with an empty body, or a corrupt cache entry served as empty.
Common situations: Text containing only emoji or invisible characters; provider quota exhausted and errors swallowed; corrupted cache entry returning an empty hit.
Related errors
- Synthesis failed: {str(e)}
- str(e)
- TTS service not available
- data?.error || data?.detail || `HTTP ${res.status}`
- (data && (data.error || data.detail)) || `HTTP ${res.status}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/9567ea84d6b19c8e.
Report an issue: GitHub.