harry0703/MoneyPrinterTurbo · error · ValueError
invalid voice name: {voice_name}
Error message
invalid voice name: {voice_name} What it means
azure_tts_v2 expects an Azure voice name ending with the '-V2' suffix; is_azure_v2_voice() strips and returns the base name only when the suffix is present, otherwise it returns an empty string. An empty result makes azure_tts_v2 log and raise ValueError. Note the bug-shaped detail: the message interpolates the already-reassigned (empty) voice_name, so the message always reads 'invalid voice name: '.
Source
Thrown at app/services/voice.py:999
return (
'<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" '
f'xml:lang="{voice_locale}">'
f'<voice name="{escaped_voice_name}">'
f'<prosody rate="{normalized_rate:g}">{escaped_text}</prosody>'
"</voice></speak>"
)
def azure_tts_v2(
text: str,
voice_name: str,
voice_file: str,
voice_rate: float = 1.0,
) -> Union[SubMaker, None]:
voice_name = is_azure_v2_voice(voice_name)
if not voice_name:
logger.error(f"invalid voice name: {voice_name}")
raise ValueError(f"invalid voice name: {voice_name}")
text = text.strip()
ssml = _build_azure_v2_ssml(text, voice_name, voice_rate)
def _format_duration_to_offset(duration) -> int:
if isinstance(duration, str):
time_obj = datetime.strptime(duration, "%H:%M:%S.%f")
milliseconds = (
(time_obj.hour * 3600000)
+ (time_obj.minute * 60000)
+ (time_obj.second * 1000)
+ (time_obj.microsecond // 1000)
)
return milliseconds * 10000
if isinstance(duration, int):
return duration
return 0View on GitHub (pinned to 1f9f19c202)
Solutions
- Pass an Azure V2 voice name, e.g. 'zh-CN-XiaoxiaoNeural-V2'.
- If the name comes from user config, validate/normalize it with is_azure_v2_voice() before calling azure_tts_v2.
- Fix the log/message to interpolate the original input (before reassignment) so failures are diagnosable: currently it always prints an empty name.
Example fix
# before azure_tts_v2(text, "zh-CN-XiaoxiaoNeural", voice_file) # after azure_tts_v2(text, "zh-CN-XiaoxiaoNeural-V2", voice_file)
Defensive patterns
Strategy: validation
Validate before calling
from app.services.voice import is_azure_v2_voice
base = is_azure_v2_voice(voice_name)
if not base:
raise ValueError(f"{voice_name!r} must be an Azure V2 voice ending in '-V2'") Type guard
def is_azure_v2_voice_name(name: str) -> bool:
"""True when name (after parsing) carries the '-V2' suffix."""
return is_azure_v2_voice(name) != "" Try / catch
try:
azure_tts_v2(text, voice_name, voice_file)
except ValueError as exc:
if "invalid voice name" in str(exc):
raise ValueError(f"use an Azure V2 voice like 'zh-CN-XiaoxiaoNeural-V2', got {voice_name!r}") from exc
raise Prevention
- Normalize voice lists in config so every Azure V2 entry carries the '-V2' suffix.
- Validate with is_azure_v2_voice() at UI/API intake, not only inside azure_tts_v2.
When it happens
Trigger: Calling azure_tts_v2(text, 'zh-CN-XiaoxiaoNeural', ...) without the '-V2' suffix; passing a voice configured for another provider (e.g. 'azure:...' or a plain name); passing an empty or whitespace voice_name.
Common situations: Voice list from config/UI uses standard Azure names without the V2 marker; user migrated settings from an older version that did not require the suffix; typo in the voice name in params.voice_name.
Related errors
- Unsupported MiniMax voice type: {voice_type}
- uploaded file must contain a decodable audio stream
- background music file is empty or missing
- background music file exceeds the 30 MB limit
- background music file is empty
AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14).
Data as JSON: /api/errors/e1eebbce90b8c23a.
Report an issue: GitHub.