SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to start crispasr (cosyvoice3-tts)

Error message

Failed to start crispasr (cosyvoice3-tts)

What it means

InvalidOperationException thrown when Process.Start(psi) returns null while launching the cosyvoice3-tts server. In modern .NET Process.Start throws on failure rather than returning null, so this guard is effectively defensive/unreachable; if hit, it means the runtime returned null for the spawned handle.

Source

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

            // filesystem lookup).
            psi.ArgumentList.Add("--voice-dir");
            psi.ArgumentList.Add(GetSetVoicesFolder());

            // Voice arg is either a baked preset name ("zero_shot", "fleurs-en", ...) or an
            // absolute path to an imported reference WAV. For WAV clones --ref-text carries
            // the spoken transcription; required by the s3tok speech tokenizer.
            psi.ArgumentList.Add("--voice");
            psi.ArgumentList.Add(voiceArg);
            if (!string.IsNullOrEmpty(refText))
            {
                psi.ArgumentList.Add("--ref-text");
                psi.ArgumentList.Add(refText);
            }

            CrispAsrTtsProvenance.AddServerMarkingArgs(psi.ArgumentList, exe);

            var process = Process.Start(psi)
                ?? throw new InvalidOperationException("Failed to start crispasr (cosyvoice3-tts)");

            var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);
            _serverLaunchCommand = launchCommand;
            Se.WriteToolsLog("CosyVoice3 (CrispASR) server starting — "
                + $"PID: {process.Id}, "
                + $"Cmd: {launchCommand}");

            lock (_serverLog) _serverLog.Clear();
            process.ErrorDataReceived += (_, e) =>
            {
                if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);
            };
            process.OutputDataReceived += (_, e) =>
            {
                if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);
            };
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Treat as a runtime/platform anomaly — check the .NET runtime version and host environment.
  2. Re-run on a supported .NET runtime where Process.Start throws on real failure (giving a more informative error).
  3. If reproducing, capture the ProcessStartInfo state and report against the runtime.
Defensive patterns

Strategy: try-catch

Try / catch

try { await cosyVoice3Engine.Speak(text, out, voice, lang, region, model, ct); }
catch (InvalidOperationException ex) when (ex.Message == "Failed to start crispasr (cosyvoice3-tts)")
{
    Se.WriteToolsLog("Runtime returned null from Process.Start; report platform/runtime anomaly.", true);
}

Prevention

When it happens

Trigger: Process.Start(psi) with the fully-built cosyvoice3-tts ProcessStartInfo evaluates to null under the null-coalescing throw. Real-world occurrence requires a platform/runtime quirk where Start returns null instead of throwing.

Common situations: Essentially unreachable on .NET 6+; hypothetically a broken Process implementation or an extremely constrained environment that returns null handles.

Related errors


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