{"record":{"id":"7fad5999e6c5a92b","repo":"jamiepine/voicebox","slug":"whisper-model-model-size-is-not-yet-downloaded","errorCode":null,"errorMessage":"Whisper model '{model_size}' is not yet downloaded. Open Voicebox → Settings → Models to download it first.","messagePattern":"Whisper model '(.+?)' is not yet downloaded\\. Open Voicebox → Settings → Models to download it first\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/mcp_server/tools.py","lineNumber":319,"sourceCode":"    from ..services import transcribe as transcribe_service\n    from ..utils.audio import load_audio\n\n    whisper = transcribe_service.get_whisper_model()\n    model_size = model or whisper.model_size\n    valid = list(WHISPER_HF_REPOS.keys())\n    if model_size not in valid:\n        raise ValueError(\n            f\"Invalid STT model '{model_size}'. Must be one of: {', '.join(valid)}\"\n        )\n\n    # load_audio is sync; keep the event loop responsive.\n    audio, sr = await asyncio.to_thread(load_audio, str(path))\n    duration = len(audio) / sr\n\n    if (\n        not whisper.is_loaded() or whisper.model_size != model_size\n    ) and not whisper._is_model_cached(model_size):\n        raise ValueError(\n            f\"Whisper model '{model_size}' is not yet downloaded. Open \"\n            \"Voicebox → Settings → Models to download it first.\"\n        )\n\n    text = await whisper.transcribe(str(path), language, model_size)\n    return {\n        \"text\": text,\n        \"duration\": duration,\n        \"language\": language,\n        \"model\": model_size,\n    }\n","sourceCodeStart":301,"sourceCodeEnd":331,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/mcp_server/tools.py#L301-L331","documentation":"Raised by _transcribe_file when the requested whisper model_size is valid but neither loaded nor cached on disk. Specifically: (whisper is not loaded OR its current model_size differs) AND whisper._is_model_cached(model_size) is False. The error points the user to the in-app downloader.","triggerScenarios":"First use of a whisper size that was never downloaded; switching to a different size (e.g. base → large) that has not been fetched yet; the cache directory was deleted or moved.","commonSituations":"Fresh install with no models pre-downloaded; offline machine where the initial download never completed; custom HF_HOME / cache dir that was wiped; selecting a heavier model than was ever pulled.","solutions":["Open Voicebox → Settings → Models and download the requested whisper size first.","Pre-download programmatically via the backend's load/ensure-cached path before calling transcribe.","Verify the cache directory is writable and persistent across restarts."],"exampleFix":"// before\nvoicebox_transcribe(audio_base64=b64, model=\"large\")  # not cached\n// after\n# in Voicebox: Settings → Models → download 'large', then\nvoicebox_transcribe(audio_base64=b64, model=\"large\")","handlingStrategy":"try-catch","validationCode":"from backend.backends import WHISPER_HF_REPOS\nwhisper = transcribe_service.get_whisper_model()\nloaded_or_cached = whisper.is_loaded() or whisper._is_model_cached(model_size)\nif not loaded_or_cached:\n    raise RuntimeError(f\"whisper {model_size!r} not downloaded; run Settings → Models\")\nawait voicebox_transcribe(audio_base64=b64, model=model_size)","typeGuard":"def whisper_model_ready(model_size: str) -> bool:\n    whisper = transcribe_service.get_whisper_model()\n    return whisper.is_loaded() or whisper._is_model_cached(model_size)","tryCatchPattern":"try:\n    await voicebox_transcribe(audio_base64=b64, model=model_size)\nexcept ValueError as exc:\n    if \"not yet downloaded\" in str(exc):\n        # trigger download / fall back to an already-cached size\n        await voicebox_transcribe(audio_base64=b64, model=None)\n    else:\n        raise","preventionTips":["Pre-download required whisper sizes from Settings → Models during provisioning.","Verify the HF cache directory is writable and persistent.","Default callers to a size that is known-cached (often 'base')."],"tags":["mcp","whisper","model-cache","download","transcription"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}