SubtitleEdit/subtitleedit · error · InvalidOperationException

F5-TTS (CrispASR) synthesis failed ({(int)response.StatusCod

Error message

F5-TTS (CrispASR) synthesis failed ({(int)response.StatusCode}): {errorBody}

What it means

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

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/F5TtsCrispAsr.cs:446

                + (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 = $"F5-TTS (CrispASR) server error {(int)response.StatusCode} {response.StatusCode} — "
                    + $"Voice: {f5Voice}, Text: {text}, RequestJson: {body}, "
                    + $"ResponseBody: {errorBody}, ServerLog: {serverLog}"
                    + LaunchCmdSuffix(launchCommand);
                Se.LogError(errMsg);
                Se.WriteToolsLog(errMsg);
                throw new InvalidOperationException(
                    $"F5-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 TryReadRefText(string wavPath)
    {
        try
        {
            var sidecar = Path.ChangeExtension(wavPath, ".txt");

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Read the status: 4xx → fix the request payload; 5xx → server/backend fault.
  2. Confirm the reference WAV is 24 kHz mono and the .txt sidecar holds the spoken transcription.
  3. On 503, wait for the server to finish loading and retry.
  4. Inspect 'Server log' for the backend stack trace behind a 500.
  5. Ensure CrispASR is current — older builds rejected absolute voice paths (HTTP 400 path-traversal guard).
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate reference WAV + sidecar before posting.
if (voice.EngineVoice is F5TtsVoice f5 && (string.IsNullOrEmpty(f5.FilePath) || !File.Exists(Path.ChangeExtension(f5.FilePath, ".txt"))))
    return new TtsResult { Text = text, FileName = string.Empty, Error = true, ErrorMessage = "F5-TTS needs a reference WAV + .txt sidecar." };

Try / catch

try { await f5TtsEngine.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 f5TtsEngine.Speak(text, out, voice, lang, region, model, ct); }
    else Se.WriteToolsLog($"F5-TTS synthesis HTTP {code}: {ex.Message}", true);
}

Prevention

When it happens

Trigger: crispasr returns 4xx/5xx for the synthesis request — HTTP 400 for a malformed request or a voice path that triggers the path-traversal guard, 422 for unsupported input, 500 for a backend fault that did not kill the process, 503 while still loading.

Common situations: The deliberate non-sending of the 'voice'/'ref_text' field was fixed so the request stays clean — but a stale server build could still reject paths; ref-text missing for a clone; 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/f34250a0d413bd9d. Report an issue: GitHub.