SubtitleEdit/subtitleedit · error · InvalidOperationException
Qwen3 TTS (CrispASR) synthesis failed ({(int)response.Status
Error message
Qwen3 TTS (CrispASR) synthesis failed ({(int)response.StatusCode}): {errorBody}{Environment.NewLine}Server log:{Environment.NewLine}{serverLog}{LaunchCmdSuffix} What it means
InvalidOperationException thrown when the crispasr /v1/audio/speech endpoint returns a non-success status. The response body is read via SafeReadErrorAsync and embedded, along with the captured server log and launch command. Detailed context (voice, text, request JSON, response body) is logged via Se.LogError before the throw.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs:868
+ (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 = $"Qwen3 TTS (CrispASR) server error {(int)response.StatusCode} {response.StatusCode} — "
+ $"Voice: {qwen3Voice}, Text: {text}, RequestJson: {body}, "
+ $"ResponseBody: {errorBody}, ServerLog: {serverLog}"
+ LaunchCmdSuffix(launchCommand);
Se.LogError(errMsg);
Se.WriteToolsLog(errMsg);
throw new InvalidOperationException(
$"Qwen3 TTS (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 FormatLaunchCommand(string exe, System.Collections.ObjectModel.Collection<string> args)
{
static string Quote(string s) =>
!string.IsNullOrEmpty(s) && s.IndexOfAny(new[] { ' ', '\t' }) >= 0
? "\"" + s.Replace("\"", "\\\"") + "\""View on GitHub (pinned to 17a9f07487)
Solutions
- Read the embedded errorBody — crispasr states the exact rejected field.
- For Clone, confirm `voice` is the extension-less stem (Path.GetFileNameWithoutExtension), never an absolute path.
- Match the language arg to a value the talker's codec_language_id supports, or omit it for auto-infer.
- Ensure an `instructions` field is present for VoiceDesign requests.
Example fix
// before — sending the full path trips the server's path-traversal guard payload["voice"] = qwen3Voice.FilePath; // after — send only the bare stem payload["voice"] = Path.GetFileNameWithoutExtension(qwen3Voice.FilePath);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure `voice` is a bare stem and an instruction is present for VoiceDesign.
if (modelKey == ModelKeyClone)
payload["voice"] = Path.GetFileNameWithoutExtension(qwen3Voice.FilePath);
if (modelKey == ModelKeyVoiceDesign && !payload.ContainsKey("instructions"))
payload["instructions"] = "a calm female voice"; Try / catch
try { response = await HttpClient.PostAsync(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("synthesis failed"))
{ Se.LogError(ex); throw; } Prevention
- Always send the bare voice stem, never a path or extension.
- Match the language arg to a codec-supported code or omit it.
- Include an instruction for VoiceDesign requests.
When it happens
Trigger: HTTP 400 for an unknown voice name or a voice value containing path separators; HTTP 500 'ref-text not set' when the transcript sidecar is missing server-side; HTTP 422 when the language code isn't supported by the talker; HTTP 404 if the OpenAI-compatible route was renamed in a newer crispasr build.
Common situations: Sending an absolute path as `voice` instead of the bare stem; selecting a language the loaded talker doesn't support; a VoiceDesign request with no instruction (the code already sends a neutral default, but a fork may not); server build mismatch.
Related errors
- VibeVoice (CrispASR) synthesis failed ({(int)response.Status
- IndexTTS (CrispASR) synthesis failed ({(int)response.StatusC
- MOSS-TTS (CrispASR) request failed — the connection to the c
- 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/d1b92584fed84e0b.
Report an issue: GitHub.