SubtitleEdit/subtitleedit · error · ArgumentException
Voice is not a GoogleVoice
Error message
Voice is not a GoogleVoice
What it means
A defensive type guard at the top of GoogleSpeech.Speak: it requires `voice.EngineVoice` to be a `GoogleVoice` instance. ArgumentException is thrown immediately if any other engine's voice type is passed, before any network call is made. This prevents a meaningless downstream cast/null-ref inside DownloadGoogleVoiceSpeak.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/GoogleSpeech.cs:161
{
var ms = new MemoryStream();
await _ttsDownloadService.DownloadGoogleVoiceList(Se.Settings.Video.TextToSpeech.GoogleKeyFile, ms, cancellationToken);
await File.WriteAllBytesAsync(Path.Combine(GetSetGoogleFolder(), JsonFileName), ms.ToArray(), cancellationToken);
return await GetVoices(language);
}
public async Task<TtsResult> Speak(
string text,
string outputFolder,
Voice voice,
TtsLanguage? language,
string? region,
string? model,
CancellationToken cancellationToken)
{
if (voice.EngineVoice is not GoogleVoice googleVoice)
{
throw new ArgumentException("Voice is not a GoogleVoice");
}
Se.WriteToolsLog($"GoogleSpeech: voice={googleVoice.Name}, languageCode={googleVoice.LanguageCode}, model={model ?? "Standard"}, textLen={text.Length}");
var ms = new MemoryStream();
var ok = await _ttsDownloadService.DownloadGoogleVoiceSpeak(
text,
googleVoice,
model ?? "Standard",
Se.Settings.Video.TextToSpeech.GoogleKeyFile,
ms,
cancellationToken);
if (!ok)
{
Se.WriteToolsLog($"GoogleSpeech: request failed (voice={googleVoice.Name})");
return new TtsResult { Text = text, FileName = string.Empty, Error = true };
}View on GitHub (pinned to 17a9f07487)
Solutions
- Verify the Voice was obtained from GoogleSpeech.GetVoices()/RefreshVoices() and not from another engine.
- Clear the persisted voice selection and re-pick a Google voice from the combo.
- If building Voice objects in code, construct GoogleVoice (with Name + LanguageCode) and assign it to voice.EngineVoice.
- Check that the engine registry maps the voice's EngineId to the GoogleSpeech instance.
Example fix
// before
var voice = new Voice { EngineVoice = someKokoroVoice };
await googleEngine.Speak(text, out, voice, ...);
// after
var voice = new Voice { EngineVoice = new GoogleVoice { Name = "en-US-Wavenet-D", LanguageCode = "en-US" } };
await googleEngine.Speak(text, out, voice, ...); Defensive patterns
Strategy: type-guard
Validate before calling
if (voice.EngineVoice is not GoogleVoice)
{
throw new InvalidOperationException($"Refusing to call GoogleSpeech with a {voice.EngineVoice?.GetType().Name} voice.");
} Type guard
static bool IsGoogleVoice(Voice v) => v.EngineVoice is GoogleVoice;
// usage
if (!IsGoogleVoice(voice)) { /* re-pick a Google voice */ return; } Try / catch
try { await googleEngine.Speak(...); }
catch (ArgumentException ex) when (ex.Message.Contains("not a GoogleVoice"))
{
// Voice/engine mismatch — clear selection and prompt user to re-pick.
ClearVoiceSelection();
} Prevention
- Always obtain Voice objects from the same engine instance that will Speak them.
- Clear the persisted voice selection when the user switches engines.
- Bind each Voice to its source EngineId so mismatches are detectable upstream.
- Unit-test cross-engine voice passing to catch regressions.
When it happens
Trigger: Passing a Voice whose EngineVoice is a KokoroVoice, AzureVoice, ElevenlabsVoice, etc. to the Google engine; a deserialized voice list whose EngineId no longer matches the engine instance; a stale voice combo selection persisted across an engine rename.
Common situations: User switched engines in the UI but the persisted selected voice belongs to the previous engine; a plugin/voice-import produced a Voice with the wrong concrete type; serialization round-trip lost the concrete subtype.
Related errors
- Voice is not an IndexTtsVoice
- Voice is not a AllTalkVoice
- Voice is not an AzureVoice
- Voice is not a ChatterboxVoice
- IndexTTS (CrispASR) requires a reference voice WAV. Import o
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/247c51f563279f7b.
Report an issue: GitHub.