SubtitleEdit/subtitleedit · error · InvalidOperationException

CosyVoice3 (CrispASR) synthesis failed ({(int)response.Statu

Error message

CosyVoice3 (CrispASR) synthesis failed ({(int)response.StatusCode}): {errorBody}

What it means

InvalidOperationException from CosyVoice3CrispAsr.Speak when the /v1/audio/speech POST returns a non-success HTTP status. The numeric status, the response body (via SafeReadErrorAsync), and the server log are all folded into the message; the detailed diagnostic is also written via Se.LogError/Se.WriteToolsLog.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/CosyVoice3CrispAsr.cs:610

                + (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 = $"CosyVoice3 (CrispASR) server error {(int)response.StatusCode} {response.StatusCode} — "
                    + $"Voice: {cosyVoice}, Text: {text}, RequestJson: {body}, "
                    + $"ResponseBody: {errorBody}, ServerLog: {serverLog}"
                    + LaunchCmdSuffix(launchCommand);
                Se.LogError(errMsg);
                Se.WriteToolsLog(errMsg);
                throw new InvalidOperationException(
                    $"CosyVoice3 (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

  1. Read the status code: 4xx → fix the request payload (language, voice, source_lang); 5xx → server/backend fault.
  2. Cross-check language/source_lang values against CosyVoice3Languages; leave empty for auto if unsupported.
  3. For zero-shot clones, ensure a reference transcription is set (the startup --ref-text).
  4. On 503, wait for the server to finish loading and retry; the health probe gates startup but not warm-up.
  5. Inspect 'Server log' for the backend-side stack trace behind a 500.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate language/source_lang against the resolver before posting.
var langArg = CosyVoice3Languages.ResolveLanguageArg(language);
if (!string.IsNullOrEmpty(langArg) && !CosyVoice3Languages.All.Any(l => l.Code == langArg))
    return new TtsResult { Text = text, FileName = string.Empty, Error = true, ErrorMessage = $"Unsupported language {langArg}" };

Try / catch

try { await cosyVoice3Engine.Speak(text, out, voice, lang, region, model, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("synthesis failed (", StringComparison.Ordinal))
{
    var code = ExtractStatusCode(ex.Message);
    if (code == 503) { await Task.Delay(TimeSpan.FromSeconds(5), ct); await cosyVoice3Engine.Speak(text, out, voice, lang, region, model, ct); }
    else Se.WriteToolsLog($"CosyVoice3 synthesis HTTP {code}: {ex.Message}", true);
}

Prevention

When it happens

Trigger: crispasr returns 4xx/5xx for the synthesis request — e.g. HTTP 400 for a malformed voice/language/source_lang combo, 422 for unsupported input, 500 for a backend error that did not kill the process, or 503 while the model is still loading.

Common situations: Sending an unsupported language code; a voice preset name the backend rejects; a zero-shot clone missing the required ref-text; the server still warming up (503); a backend bug returning 500.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/a8de7edf6144463e. Report an issue: GitHub.