SubtitleEdit/subtitleedit · error · InvalidOperationException
Qwen3 TTS synthesis failed ({(int)response.StatusCode}): {er
Error message
Qwen3 TTS synthesis failed ({(int)response.StatusCode}): {errorBody} What it means
Thrown when the qwen3-tts-server returns a non-success HTTP status from /v1/synthesize or /v1/synthesize_with_voice. The server's response body is read via SafeReadErrorAsync and embedded in the message; the detailed voice/text/body context is logged separately via Se.LogError before the throw.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCpp.cs:276
var msg = $"Qwen3 TTS request failed: {ex.Message}"
+ (serverOutput.Length == 0 ? string.Empty : $"{Environment.NewLine}Server output:{Environment.NewLine}{serverOutput}");
Se.LogError(ex, msg);
Se.WriteToolsLog(msg);
throw new InvalidOperationException(msg, ex);
}
using (response)
{
if (!response.IsSuccessStatusCode)
{
var errorBody = await SafeReadErrorAsync(response, cancellationToken);
var serverOutput = SnapshotServerStderr();
var errMsg = $"Qwen3 TTS server error {(int)response.StatusCode} {response.StatusCode} - "
+ $"Voice: {qwen3Voice}, Text: {text}, Body: {errorBody}"
+ (serverOutput.Length == 0 ? string.Empty : $"{Environment.NewLine}Server output:{Environment.NewLine}{serverOutput}");
Se.LogError(errMsg);
Se.WriteToolsLog(errMsg);
throw new InvalidOperationException(
$"Qwen3 TTS synthesis failed ({(int)response.StatusCode}): {errorBody}");
}
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 async Task<HttpResponseMessage> SynthesizeAsync(string text, string instruction, CancellationToken ct)
{
object payload = string.IsNullOrEmpty(instruction)
? new { text }
: new { text, instruction };
var body = JsonSerializer.Serialize(payload);
using var content = new StringContent(body, Encoding.UTF8, "application/json");View on GitHub (pinned to 17a9f07487)
Solutions
- Inspect the embedded errorBody — the server states exactly which field/value it rejected.
- Match the endpoint to the model: only the VoiceDesign model accepts instruction; Base models use /v1/synthesize_with_voice with the reference audio.
- Normalize the reference WAV to 24 kHz mono 16-bit PCM with ffmpeg, then retry.
- If 500 persists with no actionable body, capture stderr (SnapshotServerStderr) and check for a model-load or Vulkan assertion in the ToolsLog.
Example fix
// before — instruction sent unconditionally to a server that may be a Base model
payload = new { text, instruction };
// after — only include instruction for the instruction-tuned model
var payload = IsVoiceDesignModel(model) && !string.IsNullOrWhiteSpace(instruction)
? new { text, instruction }
: new { text }; Defensive patterns
Strategy: try-catch
Validate before calling
// Only send instruction to the instruction-tuned (VoiceDesign) model.
var sendInstruction = IsVoiceDesignModel(model) && !string.IsNullOrWhiteSpace(instruction);
// Normalize the reference WAV to 24 kHz mono before sending.
if (!string.IsNullOrEmpty(qwen3Voice.FilePath))
EnsureWavFormat(qwen3Voice.FilePath, sampleRate: 24000, channels: 1); Try / catch
try { response = await SynthesizeAsync(inputText, instruction, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("synthesis failed"))
{
// Inspect the embedded status code + errorBody, then degrade gracefully.
Se.LogError(ex);
throw;
} Prevention
- Match the endpoint and instruction field to the model variant.
- Normalize reference audio to the server's expected sample rate/channels.
- Log the full request payload on failure so the rejected field is identifiable.
When it happens
Trigger: HTTP 400 for malformed text or an unsupported instruction field; HTTP 500 when the server's model failed to initialise or the reference WAV is the wrong format; HTTP 422 when instruction is sent to a non-instruction-tuned (0.6B/1.7B Base) model; HTTP 404 if the endpoint path drifts between server builds.
Common situations: Sending an instruction to a Base model (the code already omits it for non-VoiceDesign models, but a stale build may not); reference WAV is not 24 kHz mono so the server rejects it; text contains code points the model's tokenizer can't handle; a server version mismatch renamed the endpoint.
Related errors
- Qwen3 TTS request failed: {ex.Message}{ServerOutput}
- Qwen3 TTS server executable not found.
- Failed to start qwen3-tts-server
- qwen3-tts-server exited during startup (code {NativeExitCode
- qwen3-tts-server did not report healthy within 120s. Last ou
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/f9efa6e3a5ab2ccb.
Report an issue: GitHub.