jamiepine/voicebox · error · ValueError

Unknown model size: {model_size}

Error message

Unknown model size: {model_size}

What it means

Raised by QwenCustomVoiceBackend._get_model_path when model_size is not a key of QWEN_CV_HF_REPOS, which only contains "1.7B" (Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice) and "0.6B" (Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice). Used to look up the CustomVoice (preset-speaker) variant of Qwen3-TTS.

Source

Thrown at backend/backends/qwen_custom_voice_backend.py:75

class QwenCustomVoiceBackend:
    """Qwen3-TTS CustomVoice backend — preset speakers with instruct control."""

    def __init__(self, model_size: str = "1.7B"):
        self.model = None
        self.model_size = model_size
        self.device = self._get_device()
        self._current_model_size: Optional[str] = None

    def _get_device(self) -> str:
        return get_torch_device(allow_xpu=True, allow_directml=True)

    def is_loaded(self) -> bool:
        return self.model is not None

    def _get_model_path(self, model_size: str) -> str:
        if model_size not in QWEN_CV_HF_REPOS:
            raise ValueError(f"Unknown model size: {model_size}")
        return QWEN_CV_HF_REPOS[model_size]

    def _is_model_cached(self, model_size: Optional[str] = None) -> bool:
        size = model_size or self.model_size
        return is_model_cached(self._get_model_path(size))

    async def load_model_async(self, model_size: Optional[str] = None) -> None:
        if model_size is None:
            model_size = self.model_size

        if self.model is not None and self._current_model_size == model_size:
            return

        if self.model is not None and self._current_model_size != model_size:
            self.unload_model()

        await asyncio.to_thread(self._load_model_sync, model_size)

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Pass "1.7B" (default) or "0.6B" to the custom-voice engine.
  2. Validate the size against QWEN_CV_HF_REPOS keys before forwarding.
  3. If the MCP caller sent an unsupported size, map it to the engine default rather than raising.

Example fix

// before
qwen_custom_voice_backend.load_model_async(model_size="4B")
// after
qwen_custom_voice_backend.load_model_async(model_size="1.7B")
Defensive patterns

Strategy: validation

Validate before calling

from backend.backends.qwen_custom_voice_backend import QWEN_CV_HF_REPOS
if model_size not in QWEN_CV_HF_REPOS:
    raise ValueError(f"model_size must be one of {sorted(QWEN_CV_HF_REPOS)}")
await cv_backend.load_model_async(model_size=model_size)

Type guard

def is_qwen_cv_size(value: str) -> bool:
    from backend.backends.qwen_custom_voice_backend import QWEN_CV_HF_REPOS
    return isinstance(value, str) and value in QWEN_CV_HF_REPOS

Try / catch

try:
    await cv_backend.load_model_async(model_size=model_size)
except ValueError as exc:
    if "Unknown model size" in str(exc):
        await cv_backend.load_model_async(model_size="1.7B")
    else:
        raise

Prevention

When it happens

Trigger: Instantiating QwenCustomVoiceBackend(model_size=...) or calling load_model_async on it with anything other than "1.7B" or "0.6B".

Common situations: Treating CustomVoice as accepting the same set as the LLM backend; passing a TTS base-engine size through unchanged when the user picked the custom-voice engine; case/whitespace drift from the MCP engine arg.

Related errors


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