SubtitleEdit/subtitleedit · error · InvalidOperationException
OmniVoice (CrispASR) synthesis failed
Error message
OmniVoice (CrispASR) synthesis failed ({(int)response.StatusCode}): {errorBody}{ServerLog}{LaunchCmdSuffix} What it means
Thrown when the crispasr omnivoice server returns an HTTP response with a non-success status code from POST /v1/audio/speech. The response body is captured via SafeReadErrorAsync, and the message includes the numeric status code, the error body, the server log snapshot, and the launch command suffix.
Solutions
- Read the errorBody in the exception — it is the server's structured error and identifies the exact field or condition that failed.
- If the error is language-related, verify the crispasr binary is v0.8.26 or newer (check the .installed.sha256 sidecar) — the download service pins v0.8.28.
- If cloning-related, re-import the reference WAV ensuring it is resampled to 24 kHz mono (the import path does this automatically, but a manually-copied file may not).
- Reset the speed setting to 1.0 in SE settings if the value was manually edited.
- Check the server log for stack traces that accompany 500 responses.
Example fix
// before — language sent unconditionally
if (!string.IsNullOrEmpty(languageArg))
payload["language"] = languageArg;
// after — guard against versions that reject unknown codes
var version = CrispAsrDownloadService.GetInstalledVersion();
if (!string.IsNullOrEmpty(languageArg) && version >= new Version(0, 8, 26))
payload["language"] = languageArg; Defensive patterns
Strategy: try-catch
Validate before calling
// Validate language support and input before the request
if (string.IsNullOrWhiteSpace(text))
throw new ArgumentException("Input text must not be empty.");
var version = CrispAsrDownloadService.GetInstalledVersion();
if (!string.IsNullOrEmpty(languageArg) && version < new Version(0, 8, 26))
Se.WriteToolsLog("Warning: language field requires crispasr v0.8.26+; current: " + version); Type guard
null
Try / catch
catch (InvalidOperationException ex) when (ex.Message.Contains("synthesis failed ("))
{
var code = ExtractStatusCode(ex.Message);
if (code == 400 && ex.Message.Contains("language"))
{ /* strip the language field and retry, or warn the user */ }
else throw;
} Prevention
- Ensure crispasr is v0.8.26+ before relying on per-request language selection.
- Keep speed within 0.25–4.0.
- Validate reference WAV is 24 kHz mono before using it for cloning.
When it happens
Trigger: The HTTP call completes but response.IsSuccessStatusCode is false. For omnivoice, common causes: 400 for an unsupported language code (the per-request 'language' field requires v0.8.26+); 400 for empty input text; 500 when the backend's inference fails internally; 422 for a speed value the server rejects.
Common situations: Sending a language code that the installed crispasr version doesn't recognize (pre-v0.8.26 ignores it, but a version between v0.8.26 and the current pin may validate and reject); the speed setting was manually edited in settings to an out-of-range value; the voice WAV path contains characters the server's file loader rejects; a reference WAV that is stereo or wrong sample rate causes a codec error returned as 500.
Related errors
- MOSS-TTS (CrispASR) synthesis failed
- OmniVoice (CrispASR) request failed — the connection to the…
- OmniVoice (CrispASR) — the crispasr server crashed during…
- CrispASR executable not found. Install CrispASR via Video →…
- crispasr (omnivoice) did not report healthy within
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/cd149bbc14ee3031.
Report an issue: GitHub.
Appendix: source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs:491
+ (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}"
+ LaunchCmdSuffix(launchCommand);
Se.LogError(errMsg);
Se.WriteToolsLog(errMsg);
throw new InvalidOperationException(
$"OmniVoice (CrispASR) synthesis failed ({(int)response.StatusCode}): {errorBody}"
+ (string.IsNullOrEmpty(serverLog) ? string.Empty : $"{Environment.NewLine}Server log:{Environment.NewLine}{serverLog}")
+ LaunchCmdSuffix(launchCommand));
}
await using var fileStream = File.Create(outputFileName);
await using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken);
await contentStream.CopyToAsync(fileStream, cancellationToken);
}
return new TtsResult(outputFileName, text);
}
private static string TryReadRefText(string wavPath)
{
try
{
var sidecar = Path.ChangeExtension(wavPath, ".txt");View on GitHub (pinned to 17a9f07487)