{"record":{"id":"f9efa6e3a5ab2ccb","repo":"SubtitleEdit/subtitleedit","slug":"qwen3-tts-synthesis-failed-int-response-statusc","errorCode":null,"errorMessage":"Qwen3 TTS synthesis failed ({(int)response.StatusCode}): {errorBody}","messagePattern":"Qwen3 TTS synthesis failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCpp.cs","lineNumber":276,"sourceCode":"            var msg = $\"Qwen3 TTS request failed: {ex.Message}\"\n                + (serverOutput.Length == 0 ? string.Empty : $\"{Environment.NewLine}Server output:{Environment.NewLine}{serverOutput}\");\n            Se.LogError(ex, msg);\n            Se.WriteToolsLog(msg);\n            throw new InvalidOperationException(msg, ex);\n        }\n\n        using (response)\n        {\n            if (!response.IsSuccessStatusCode)\n            {\n                var errorBody = await SafeReadErrorAsync(response, cancellationToken);\n                var serverOutput = SnapshotServerStderr();\n                var errMsg = $\"Qwen3 TTS server error {(int)response.StatusCode} {response.StatusCode} - \"\n                    + $\"Voice: {qwen3Voice}, Text: {text}, Body: {errorBody}\"\n                    + (serverOutput.Length == 0 ? string.Empty : $\"{Environment.NewLine}Server output:{Environment.NewLine}{serverOutput}\");\n                Se.LogError(errMsg);\n                Se.WriteToolsLog(errMsg);\n                throw new InvalidOperationException(\n                    $\"Qwen3 TTS synthesis failed ({(int)response.StatusCode}): {errorBody}\");\n            }\n\n            await using var fileStream = File.Create(outputFileName);\n            await using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken);\n            await contentStream.CopyToAsync(fileStream, cancellationToken);\n        }\n\n        return new TtsResult(outputFileName, text);\n    }\n\n    private static async Task<HttpResponseMessage> SynthesizeAsync(string text, string instruction, CancellationToken ct)\n    {\n        object payload = string.IsNullOrEmpty(instruction)\n            ? new { text }\n            : new { text, instruction };\n        var body = JsonSerializer.Serialize(payload);\n        using var content = new StringContent(body, Encoding.UTF8, \"application/json\");","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCpp.cs#L258-L294","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — instruction sent unconditionally to a server that may be a Base model\npayload = new { text, instruction };\n\n// after — only include instruction for the instruction-tuned model\nvar payload = IsVoiceDesignModel(model) && !string.IsNullOrWhiteSpace(instruction)\n    ? new { text, instruction }\n    : new { text };","handlingStrategy":"try-catch","validationCode":"// Only send instruction to the instruction-tuned (VoiceDesign) model.\nvar sendInstruction = IsVoiceDesignModel(model) && !string.IsNullOrWhiteSpace(instruction);\n// Normalize the reference WAV to 24 kHz mono before sending.\nif (!string.IsNullOrEmpty(qwen3Voice.FilePath))\n    EnsureWavFormat(qwen3Voice.FilePath, sampleRate: 24000, channels: 1);","typeGuard":null,"tryCatchPattern":"try { response = await SynthesizeAsync(inputText, instruction, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"synthesis failed\"))\n{\n    // Inspect the embedded status code + errorBody, then degrade gracefully.\n    Se.LogError(ex);\n    throw;\n}","preventionTips":["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."],"tags":["tts","qwen3-tts","http-status","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}