SubtitleEdit/subtitleedit · error · InvalidOperationException
OmniVoice (CrispASR) request failed — the connection to the
Error message
OmniVoice (CrispASR) request failed — the connection to the crispasr server was dropped.
What it means
Thrown inside the catch(HttpRequestException) handler in OmniVoiceCrispAsr.Speak when the POST to the local crispasr omnivoice server fails and _serverProcess?.HasExited is false (the 'connection dropped' branch). The server process is still alive but the HTTP connection was reset or timed out. This is the omnivoice analogue of error 240.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs:469
response = await HttpClient.PostAsync($"{ServerBaseUrl}/v1/audio/speech", content, cancellationToken);
}
catch (HttpRequestException ex)
{
var serverLog = SnapshotServerLog();
var launchCommand = _serverLaunchCommand;
var died = _serverProcess?.HasExited == true;
if (died)
{
StopServerInternal();
}
var failMsg = $"OmniVoice (CrispASR) request failed — Voice: {omniVoice}, Text: {text}, "
+ $"RequestJson: {body}, ServerExited: {died}, ServerLog: {serverLog}"
+ LaunchCmdSuffix(launchCommand);
Se.LogError(ex, failMsg);
Se.WriteToolsLog(failMsg);
throw new InvalidOperationException(
(died
? "OmniVoice (CrispASR) — the crispasr server crashed during synthesis."
: "OmniVoice (CrispASR) request failed — the connection to the crispasr server was dropped.")
+ (string.IsNullOrEmpty(serverLog) ? string.Empty : $"{Environment.NewLine}Server log:{Environment.NewLine}{serverLog}")
+ LaunchCmdSuffix(launchCommand),
ex);
}
using (response)
{
if (!response.IsSuccessStatusCode)
{
var errorBody = await SafeReadErrorAsync(response, cancellationToken);
var serverLog = SnapshotServerLog();
var launchCommand = _serverLaunchCommand;
var errMsg = $"OmniVoice (CrispASR) server error {(int)response.StatusCode} {response.StatusCode} — "
+ $"Voice: {omniVoice}, Text: {text}, RequestJson: {body}, "
+ $"ResponseBody: {errorBody}, ServerLog: {serverLog}"View on GitHub (pinned to 17a9f07487)
Solutions
- Check the server log snapshot in the exception for any warnings about memory or queue overflow.
- Retry the synthesis — the server is still alive, so a transient connection drop may resolve on the next attempt without a full restart.
- Reduce input text length or split into smaller chunks.
- If using a cloned voice, verify the reference WAV is short (3-10s) — a very long reference increases codec load per request.
- Ensure adequate system RAM; the omnivoice backend's codec runs on CPU even on GPU systems.
Example fix
// before — single attempt, any drop is fatal
await engine.Speak(text, ...);
// after — retry once for a transient connection drop (server still alive)
async Task<TtsResult> SpeakWithRetry(string text, ...)
{
for (int i = 0; i < 2; i++)
{
try { return await engine.Speak(text, ...); }
catch (InvalidOperationException ex) when (i == 0 && ex.Message.Contains("connection"))
{ await Task.Delay(2000, ct); }
}
throw;
} Defensive patterns
Strategy: retry
Validate before calling
// Probe server health before a batch run
if (_serverProcess is { HasExited: false })
{
if (!await ProbeHealthAsync(_serverPort, TimeSpan.FromSeconds(2), ct))
{
Se.WriteToolsLog("Server alive but not responding to /health; will respawn.");
OmniVoiceCrispAsr.StopServer();
}
} Type guard
null
Try / catch
catch (InvalidOperationException ex) when (ex.InnerException is HttpRequestException hre)
{
// Server still alive, connection dropped — transient. Retry once.
if (attempt < maxRetries && _serverProcess?.HasExited == false)
{ await Task.Delay(2000, ct); goto retry; }
throw;
} Prevention
- Split long input text into chunks to reduce per-request load time.
- Avoid concurrent Speak calls — the backend is single-threaded for inference.
- Ensure adequate system RAM; the omnivoice codec runs on CPU even on GPU systems.
When it happens
Trigger: HttpClient.PostAsync raises HttpRequestException while the omnivoice server process is still running. The TCP connection was dropped without the process exiting: a socket RST from the OS, the HttpClient's 30-minute timeout firing, or the server's accept loop stalling under load.
Common situations: Synthesizing a very long line that causes the server's HTTP handler to time out; concurrent Speak calls overwhelming the single-threaded backend; loopback connection killed by a security product; the server is alive but thrashing on swap and cannot service the request within the HttpClient timeout.
Related errors
- MOSS-TTS (CrispASR) request failed — the connection to the c
- OmniVoice (CrispASR) — the crispasr server crashed during sy
- OmniVoice (CrispASR) synthesis failed ({(int)response.Status
- MOSS-TTS (CrispASR) synthesis failed ({(int)response.StatusC
- CrispASR executable not found. Install CrispASR via Video →
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/068069e6dba099f1.
Report an issue: GitHub.