jamiepine/voicebox · warning · HTTPException
Invalid model size '{model_size}'. Must be one of: {', '.joi
Error message
Invalid model size '{model_size}'. Must be one of: {', '.join(valid_sizes)} What it means
Raised (HTTP 400) by POST /transcribe when the effective model_size is not a key in WHISPER_HF_REPOS. model_size resolves to the `model` form field if provided, otherwise to the currently loaded whisper model's model_size. So the error can fire even when the client omits `model`, if the server's configured default is invalid. The valid set is the WHISPER_HF_REPOS keys (e.g. tiny/base/small/medium/large variants).
Source
Thrown at backend/routes/transcription.py:62
duration = len(audio) / sr
# The STT backend (mlx_audio.stt -> miniaudio) only decodes
# WAV/FLAC/MP3/Vorbis, so browser recordings uploaded as WebM/Opus
# fail with "unsupported file format" (issue: web-mode dictation).
# librosa already decoded the file above (it falls back to
# audioread/ffmpeg for exotic containers), so re-encode that PCM to a
# temp WAV and hand *that* to Whisper. WAV inputs pass through
# unchanged.
if file_suffix != ".wav":
stt_path = f"{tmp_path}.stt.wav"
await asyncio.to_thread(save_audio, audio, stt_path, sr)
whisper_model = transcribe.get_whisper_model()
model_size = model if model else whisper_model.model_size
valid_sizes = list(WHISPER_HF_REPOS.keys())
if model_size not in valid_sizes:
raise HTTPException(
status_code=400,
detail=f"Invalid model size '{model_size}'. Must be one of: {', '.join(valid_sizes)}",
)
already_loaded = whisper_model.is_loaded() and whisper_model.model_size == model_size
if not already_loaded and not whisper_model._is_model_cached(model_size):
progress_model_name = f"whisper-{model_size}"
task_manager = get_task_manager()
async def download_whisper_background():
try:
await whisper_model.load_model_async(model_size)
task_manager.complete_download(progress_model_name)
except Exception as e:
task_manager.error_download(progress_model_name, str(e))
task_manager.start_download(progress_model_name)
create_background_task(download_whisper_background())View on GitHub (pinned to 51f49dea19)
Solutions
- Fetch the accepted model list from the backend (STT model configs endpoint) and present only those to the user.
- If hit when omitting model, fix the server's default whisper model_size to a value present in WHISPER_HF_REPOS.
- After upgrading the backend, re-check WHISPER_HF_REPOS keys and align any saved settings.
- Strip version suffixes the backend doesn't register (e.g. send 'large' not 'large-v3' if only 'large' is a key).
Example fix
# before
whisper_model = transcribe.get_whisper_model()
model_size = model if model else whisper_model.model_size
if model_size not in valid_sizes:
raise HTTPException(400, f"Invalid model size '{model_size}'...")
# after (validate explicitly + fail fast on a bad default)
if model is not None and model not in valid_sizes:
raise HTTPException(400, f"Invalid model '{model}'. Must be one of: {', '.join(valid_sizes)}")
model_size = model or whisper_model.model_size
assert model_size in valid_sizes, f"server default model '{model_size}' not in WHISPER_HF_REPOS" Defensive patterns
Strategy: validation
Validate before calling
async function transcribeSafe(api, file, language, model) {
const allowed = await api.getSttModelConfigs().then(r => r.map(c => c.id));
const chosen = model ?? defaultSttModel;
if (!allowed.includes(chosen)) {
throw new Error(`model must be one of ${allowed.join(', ')}`);
}
return api.transcribe(file, language, model);
} Type guard
function isValidModelSize(allowed, m) {
return Array.isArray(allowed) && typeof m === 'string' && allowed.includes(m);
} Try / catch
try { await api.transcribe(file, language, model); }
catch (e) {
if (e.status === 400 && /Invalid model size/.test(e.detail)) {
refreshModelList(); // pick from current set
} else if (e.status === 202) {
notify('Model downloading; retry shortly');
} else throw e;
} Prevention
- Source the accepted model sizes from the backend, not a hardcoded client list.
- After an upgrade, re-align any persisted default STT model with WHISPER_HF_REPOS keys.
- Omit `model` to use the server default only after confirming that default is valid.
When it happens
Trigger: POST /transcribe with model="large-v3" when the build only ships keys like tiny/base/small; or omitting model while the server's default whisper model_size is set to a value not present in WHISPER_HF_REPOS (mismatched config after an upgrade).
Common situations: Version skew: WHISPER_HF_REPOS was narrowed (a model dropped) but a persisted default still references it; client hardcodes a model id that the backend doesn't register; typo in the model form field.
Related errors
- Invalid STT model '{model_size}'. Must be one of: {', '.join
- str(e)
- Pass exactly one of `audio_base64` or `audio_path`.
- `audio_path` must be absolute.
- Invalid audio_base64: {exc}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/64ae72bef9a23947.
Report an issue: GitHub.