calesthio/OpenMontage · error · ValueError
model_id must be one of: {choices}
Error message
model_id must be one of: {choices} What it means
Raised by fal_elevenlabs_tts._resolve_model when the requested model_id (after alias mapping) is not a key in _MODELS. The wrapper whitelists supported ElevenLabs models on fal.ai and maps aliases first, so this only fires for genuinely unknown names.
Source
Thrown at tools/audio/fal_elevenlabs_tts.py:215
"writes an audio file to output_path",
"submits one paid fal.ai ElevenLabs speech request",
]
user_visible_verification = [
"Listen to the generated voice sample before approving full narration",
]
def _get_api_key(self) -> str | None:
return os.environ.get("FAL_KEY") or os.environ.get("FAL_AI_API_KEY")
def get_status(self) -> ToolStatus:
return ToolStatus.AVAILABLE if self._get_api_key() else ToolStatus.UNAVAILABLE
def _resolve_model(self, requested: str | None) -> tuple[str, str]:
model_name = requested or "eleven-v3"
model_name = self._MODEL_ALIASES.get(model_name, model_name)
if model_name not in self._MODELS:
choices = ", ".join(self._MODELS)
raise ValueError(f"model_id must be one of: {choices}")
return model_name, self._MODELS[model_name]
def estimate_cost(self, inputs: dict[str, Any]) -> float:
model_name, _ = self._resolve_model(inputs.get("model_id"))
return round(
len(inputs.get("text", "")) * self._PRICE_PER_CHARACTER[model_name],
4,
)
@staticmethod
def _output_extension(output_format: str) -> str:
return {
"mp3": "mp3",
"pcm": "pcm",
"opus": "opus",
}.get(output_format.split("_", 1)[0], "audio")
def execute(self, inputs: dict[str, Any]) -> ToolResult:View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Use one of the listed choices — typically 'eleven-v3' (the default) or 'eleven-multilingual-v2'
- If an alias should exist, add the mapping to _MODEL_ALIASES in fal_elevenlabs_tts.py
- Omit model_id entirely to get the default eleven-v3
Example fix
// before
inputs = {"text": "hi", "model_id": "tts-1"} # raises
// after
inputs = {"text": "hi", "model_id": "eleven-v3"} Defensive patterns
Strategy: type-guard
Validate before calling
valid = set(tool._MODELS) | set(tool._MODEL_ALIASES)
if inputs.get("model_id") and inputs["model_id"] not in valid:
inputs["model_id"] = "eleven-v3" # or surface a choice list Type guard
def is_valid_fal_tts_model(model_id: str | None, tool) -> bool:
name = tool._MODEL_ALIASES.get(model_id, model_id)
return name in tool._MODELS Prevention
- Pin model names to the tool's whitelist, not to upstream marketing names
- Omit model_id to use the safe default
- On tool updates, re-check _MODELS before shipping config changes
When it happens
Trigger: Passing model_id like 'eleven-turbo-v2-5' or 'tts-1' that is neither in _MODEL_ALIASES nor _MODELS; also raised from estimate_cost, so cost-checking a bad model fails the same way.
Common situations: Copy-pasting model names from OpenAI or ElevenLabs native docs that fal.ai does not host; new model released upstream before this wrapper's whitelist is updated; typo in a config file.
Related errors
- duration_seconds is required for cost estimation
- text is required
- text exceeds Kling TTS safety limit of 5000 characters
- voice_id is required for Kling official TTS
- voice_language must be one of: {', '.join(TTS_LANGUAGES)}
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/c8748adfe6e8dec1.
Report an issue: GitHub.