jamiepine/voicebox · error · HTTPException

{e}

Error message

{e}

What it means

500 from POST /models/load. The endpoint calls tts.get_tts_model().load_model_async(model_size) inside a bare except Exception and re-raises with detail=str(e) — i.e. the raw exception text is forwarded to the client. model_size defaults to '1.7B' (a query parameter, not a JSON body). Failure modes include unsupported size for the current backend, network/HuggingFace download errors, VRAM exhaustion, and weight-loading failures.

Source

Thrown at backend/routes/models.py:60

                copied_so_far,
                total_bytes,
                filename=item.name,
                status="downloading",
            )
    return copied_so_far


@router.post("/models/load")
async def load_model(model_size: str = "1.7B"):
    """Manually load TTS model."""
    from ..services import tts

    try:
        tts_model = tts.get_tts_model()
        await tts_model.load_model_async(model_size)
        return {"message": f"Model {model_size} loaded successfully"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/models/unload")
async def unload_model():
    """Unload the default Qwen TTS model to free memory."""
    from ..services import tts

    try:
        tts.unload_tts_model()
        return {"message": "Model unloaded successfully"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/models/{model_name}/unload")
async def unload_model_by_name(model_name: str):
    """Unload a specific model from memory without deleting it from disk."""
    from ..backends import get_model_config, unload_model_by_config

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Read the detail string — this endpoint leaks the underlying message, which usually names the real cause (size unsupported, network, OOM).
  2. Call GET /models/status to see which sizes are valid and already cached before loading.
  3. Free memory first with POST /models/unload, then retry the load.
  4. Confirm the model_size matches a registry value (e.g. 0.6B/1.7B/4B for Qwen TTS) and that your backend type supports it.

Example fix

# before
curl -X POST 'http://localhost:8000/models/load?model_size=7B'
# after
curl -X POST 'http://localhost:8000/models/load?model_size=1.7B'
Defensive patterns

Strategy: validation

Validate before calling

const VALID_TTS_SIZES = ['0.6B','1.7B','4B']; // confirm against GET /models/status
async function loadTts(size: string) {
  if (!VALID_TTS_SIZES.includes(size)) throw new Error(`Unsupported size: ${size}`);
  const res = await fetch(`/models/load?model_size=${encodeURIComponent(size)}`, {method:'POST'});
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`Load failed: ${err.detail ?? res.status}`);
  }
  return res.json();
}

Try / catch

try {
  await loadTts('1.7B');
} catch (e) {
  // e.message contains the leaked detail — inspect for OOM/network/unsupported-size
  if (/out of memory|VRAM|CUDA/i.test(e.message)) { await fetch('/models/unload',{method:'POST'}); await loadTts('0.6B'); }
  else throw e;
}

Prevention

When it happens

Trigger: POST /models/load?model_size=7B (unsupported size); load while offline and the size isn't cached; load a size that exceeds available VRAM; concurrent load already in progress; mlx backend asked for a pytorch-only size.

Common situations: First-run download on a flaky connection; wrong default size after a backend switch (mlx vs pytorch); user manually invoked load on a size the registry doesn't expose; disk full in the HF cache.

Related errors


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