SubtitleEdit/subtitleedit · error · InvalidOperationException
Failed to start crispasr (omnivoice)
Error message
Failed to start crispasr (omnivoice)
What it means
InvalidOperationException thrown if Process.Start(psi) returns null when launching the crispasr omnivoice server. As with error 243, this null-return path is practically unreachable because UseShellExecute is false — Process.Start either returns a Process or throws Win32Exception. The guard is purely defensive.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs:639
psi.ArgumentList.Add("--port");
psi.ArgumentList.Add(port.ToString());
psi.ArgumentList.Add("--voice-dir");
psi.ArgumentList.Add(GetSetVoicesFolder());
CrispAsrTtsProvenance.AddServerMarkingArgs(psi.ArgumentList, exe);
if (!string.IsNullOrEmpty(voicePath))
{
psi.ArgumentList.Add("--voice");
psi.ArgumentList.Add(voicePath);
if (!string.IsNullOrEmpty(refText))
{
psi.ArgumentList.Add("--ref-text");
psi.ArgumentList.Add(refText);
}
}
var process = Process.Start(psi)
?? throw new InvalidOperationException("Failed to start crispasr (omnivoice)");
var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);
_serverLaunchCommand = launchCommand;
Se.WriteToolsLog("OmniVoice (CrispASR) server starting — "
+ $"PID: {process.Id}, "
+ $"Cmd: {launchCommand}");
lock (_serverLog) _serverLog.Clear();
process.ErrorDataReceived += (_, e) =>
{
if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);
};
process.OutputDataReceived += (_, e) =>
{
if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);
};
process.BeginErrorReadLine();
process.BeginOutputReadLine();View on GitHub (pinned to 17a9f07487)
Solutions
- Verify ProcessStartInfo.UseShellExecute is still false — if changed to true, this path becomes live.
- If genuinely null, wrap in a try/catch for Win32Exception instead, since that is the realistic error.
- Log the full psi state (FileName, Arguments, WorkingDirectory) to diagnose.
- Retry once — a transient OS resource limit can occasionally cause process creation to fail.
Example fix
// before
var process = Process.Start(psi)
?? throw new InvalidOperationException("Failed to start crispasr (omnivoice)");
// after — handle the realistic exception types
Process process;
try { process = Process.Start(psi); }
catch (Win32Exception ex)
{
throw new InvalidOperationException(
$"Failed to start crispasr (omnivoice): {ex.Message}", ex);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify binary exists before Process.Start
var exe = GetCrispAsrExecutable();
if (!File.Exists(exe)) throw new FileNotFoundException("Missing: " + exe, exe); Type guard
null
Try / catch
catch (InvalidOperationException ex) when (ex.Message == "Failed to start crispasr (omnivoice)")
{
Se.LogError(ex, "Process.Start returned null unexpectedly.");
throw;
} Prevention
- This path is dead code with UseShellExecute=false; focus on Win32Exception.
- Verify binary path and execute permissions before calling Process.Start.
- Log the full ProcessStartInfo on failure for diagnosis.
When it happens
Trigger: Process.Start(psi) returns null. With the configured ProcessStartInfo (UseShellExecute=false), this does not occur in practice. A Win32Exception is the real failure mode when the binary cannot execute.
Common situations: Effectively unreachable in production. If observed, it points to a framework anomaly, a modified ProcessStartInfo, or a hypothetical future API change.
Related errors
- Failed to start crispasr (moss-tts)
- crispasr (omnivoice) exited during startup (code {exitCode})
- Failed to start omnivoice-tts
- crispasr (moss-tts) exited during startup (code {exitCode}).
- OmniVoice (CrispASR) — the crispasr server crashed during sy
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/b6321f140847e916.
Report an issue: GitHub.