jamiepine/voicebox · error · HTTPException

LLM produced empty output; nothing to speak.

Error message

LLM produced empty output; nothing to speak.

What it means

Returned as HTTP 500 by POST /generate. After a successful personality rewrite, the route strips the result text and checks `if not text`. If the LLM returned only whitespace or an empty string, there is nothing to send to TTS, so it raises this 500. It is a server-side quality gate: the LLM produced no usable content.

Source

Thrown at backend/routes/generations.py:88

    engine = _resolve_generation_engine(data, profile)
    try:
        profiles.validate_profile_engine(profile, engine)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

    model_size = (data.model_size or "1.7B") if engine_has_model_sizes(engine) else None

    text = data.text
    source = "manual"
    if data.personality and getattr(profile, "personality", None):
        try:
            llm_result = await personality.rewrite_as_profile(profile.personality, data.text)
        except ValueError as e:
            raise HTTPException(status_code=400, detail=str(e))
        text = llm_result.text.strip()
        if not text:
            raise HTTPException(status_code=500, detail="LLM produced empty output; nothing to speak.")
        source = "personality_speak"

    generation = await history.create_generation(
        profile_id=data.profile_id,
        text=text,
        language=data.language,
        audio_path="",
        duration=0,
        seed=data.seed,
        db=db,
        instruct=data.instruct,
        generation_id=generation_id,
        status="generating",
        engine=engine,
        model_size=model_size if engine_has_model_sizes(engine) else None,
        source=source,
    )

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Retry the request — transient empty output from the LLM often clears on retry.
  2. Inspect the personality prompt and relax constraints that may force empty/refusal output.
  3. Temporarily disable personality (personality=false) to send the original text to TTS.
  4. If persistent, capture the raw LLM response in the personality service logs to diagnose the empty completion.

Example fix

// before: single attempt, surface 500 to user
const r = await post('/generate', { profile_id, text, personality: true });
// after: retry once, then fall back to raw text
try {
  await post('/generate', { profile_id, text, personality: true });
} catch (e) {
  if (e.status === 500) await post('/generate', { profile_id, text, personality: false });
}
Defensive patterns

Strategy: retry

Validate before calling

# Pre-flight: confirm the personality rewrite produces non-empty text.
result = await personality.rewrite_as_profile(profile.personality, data.text)
if not (result.text or '').strip():
    # would 500 — retry once, then fall back to raw text
    data.personality = False

Type guard

def rewrite_is_usable(text: str) -> bool:
    return bool(text and text.strip())

Try / catch

try:
    client.post('/generate', json=payload)
except HTTPStatusError as e:
    if e.response.status_code == 500 and 'empty output' in e.response.json().get('detail', ''):
        # retry once, then fall back to raw text without personality
        try:
            client.post('/generate', json=payload)
        except HTTPStatusError:
            payload['personality'] = False
            client.post('/generate', json=payload)
        return
    raise

Prevention

When it happens

Trigger: Personality rewrite returns an empty string; the LLM returns only whitespace/punctuation that strips to empty; a model misconfiguration causes the rewrite to yield blank output; prompt injection causes the model to refuse with an empty response.

Common situations: LLM provider returning empty completions under load or quota pressure; a personality prompt that over-constrains the model into silence; upstream model returning a refusal that the adapter reduces to empty; whitespace-only output from a misconfigured streaming adapter.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/03281548e5824ee9. Report an issue: GitHub.