{"record":{"id":"d72242b89420aef6","repo":"jamiepine/voicebox","slug":"invalid-stt-model-model-size-must-be-one-of","errorCode":null,"errorMessage":"Invalid STT model '{model_size}'. Must be one of: {', '.join(valid)}","messagePattern":"Invalid STT model '(.+?)'\\. Must be one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/mcp_server/tools.py","lineNumber":308,"sourceCode":"        else None,\n    }\n\n\n# ─── Transcribe helper ─────────────────────────────────────────────────────\n\n\nasync def _transcribe_file(\n    path: Path, language: str | None, model: str | None\n) -> dict[str, Any]:\n    from ..backends import WHISPER_HF_REPOS\n    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,","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/mcp_server/tools.py#L290-L326","documentation":"Raised by _transcribe_file when the resolved model_size is not a key of WHISPER_HF_REPOS, whose keys are \"base\", \"small\", \"medium\", \"large\", and \"turbo\". model_size defaults to the whisper backend's current model_size if the caller did not pass model=.","triggerScenarios":"Passing model=\"tiny\"/\"medium-v2\"/\"large-v3\" directly (only the five mapped keys are accepted); passing a TTS-style size like \"1.7B\"; relying on a default that was misconfigured elsewhere.","commonSituations":"Using OpenAI whisper model names that are not in the allowlist (e.g. 'tiny', 'large-v2'); copying a size token from the TTS engines; the stored default whisper size was changed to an unsupported value.","solutions":["Pass one of: \"base\", \"small\", \"medium\", \"large\", \"turbo\".","Omit the model argument to use the loaded default.","If you need a specific openai/whisper-* variant not listed, extend WHISPER_HF_REPOS rather than passing its short name."],"exampleFix":"// before\nvoicebox_transcribe(audio_base64=b64, model=\"tiny\")\n// after\nvoicebox_transcribe(audio_base64=b64, model=\"base\")","handlingStrategy":"validation","validationCode":"from backend.backends import WHISPER_HF_REPOS\nif model is not None and model not in WHISPER_HF_REPOS:\n    raise ValueError(f\"model must be one of {sorted(WHISPER_HF_REPOS)} or None\")\nawait voicebox_transcribe(audio_base64=b64, model=model)","typeGuard":"def is_valid_whisper_model(value: str | None) -> bool:\n    from backend.backends import WHISPER_HF_REPOS\n    return value is None or (isinstance(value, str) and value in WHISPER_HF_REPOS)","tryCatchPattern":"try:\n    await voicebox_transcribe(audio_base64=b64, model=model)\nexcept ValueError as exc:\n    if \"Invalid STT model\" in str(exc):\n        await voicebox_transcribe(audio_base64=b64, model=None)  # use default\n    else:\n        raise","preventionTips":["Validate against WHISPER_HF_REPOS keys rather than a hand-maintained list.","Omit model= to use the loaded default when in doubt.","Remember only base/small/medium/large/turbo are accepted — not 'tiny' or 'large-v2'."],"tags":["mcp","whisper","model-selection","validation","transcription"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}