jamiepine/voicebox · error · HTTPException
Model {model_size} is not downloaded yet. Use /generate to t
Error message
Model {model_size} is not downloaded yet. Use /generate to trigger a download. What it means
The detail string of the same HTTPException as error 35 — the f-string `f"Model {model_size} is not downloaded yet..."` passed to detail= for qwen/qwen_custom_voice/tada engines when _is_model_cached(model_size) is False. Same root cause and recovery; the {model_size} placeholder interpolates the requested size so the client knows which size is missing.
Source
Thrown at backend/backends/__init__.py:554
await backend.load_model()
async def ensure_model_cached_or_raise(engine: str, model_size: str = "default") -> None:
"""Check if a model is cached, raise HTTPException if not. Used by streaming endpoint."""
from fastapi import HTTPException
backend = get_tts_backend_for_engine(engine)
cfg = None
for c in get_tts_model_configs():
if c.engine == engine and c.model_size == model_size:
cfg = c
break
if engine in ("qwen", "qwen_custom_voice", "tada"):
if not backend._is_model_cached(model_size):
raise HTTPException(
status_code=400,
detail=f"Model {model_size} is not downloaded yet. Use /generate to trigger a download.",
)
else:
if not backend._is_model_cached():
display = cfg.display_name if cfg else engine
raise HTTPException(
status_code=400,
detail=f"{display} model is not downloaded yet. Use /generate to trigger a download.",
)
def unload_model_by_config(config: ModelConfig) -> bool:
"""Unload a model given its config. Returns True if it was loaded, False otherwise."""
from . import get_tts_backend_for_engine
from ..services import tts, transcribe, llm as llm_service
if config.engine == "whisper":
whisper_model = transcribe.get_whisper_model()
if whisper_model.is_loaded() and whisper_model.model_size == config.model_size:View on GitHub (pinned to 51f49dea19)
Solutions
- Trigger the download via the /generate endpoint for the exact engine+model_size first.
- Pre-fetch all needed sizes during onboarding.
- Confirm the cache path and that _is_model_cached(model_size) detects the expected file layout.
- List cached sizes in the response so clients can choose an available one.
Example fix
# before
detail=f"Model {model_size} is not downloaded yet. Use /generate to trigger a download."
# after
detail=f"Model '{model_size}' for engine '{engine}' is not downloaded yet. Use /generate to trigger a download." Defensive patterns
Strategy: validation
Validate before calling
def is_model_cached(engine: str, model_size: str) -> bool:
backend = get_tts_backend_for_engine(engine)
if engine in ('qwen', 'qwen_custom_voice', 'tada'):
return backend._is_model_cached(model_size)
return backend._is_model_cached()
# Before streaming:
if not is_model_cached(engine, model_size):
await load_engine_model(engine, model_size) Try / catch
from fastapi import HTTPException
try:
await ensure_model_cached_or_raise(engine, model_size)
except HTTPException as e:
if e.status_code == 400:
await load_engine_model(engine, model_size)
else:
raise Prevention
- Check _is_model_cached(model_size) before the streaming call and trigger /generate when missing.
- Keep model sizes consistent between the client request and the cache layout.
- Pre-fetch non-default sizes the client may request.
When it happens
Trigger: Streaming endpoint invoked for engine in {qwen, qwen_custom_voice, tada} with a model_size whose weights are absent from the cache directory; _is_model_cached(model_size) returns False.
Common situations: Client requests a size (e.g. '0.6B') before downloading it. Cache wiped. Multiple-size engine where only the default size was pre-fetched.
Related errors
- Model ${model_size} is not downloaded yet. Use /generate to
- {display} model is not downloaded yet. Use /generate to trig
- Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.k
- Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.k
- {e}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/d9570b261c180f4c.
Report an issue: GitHub.