SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to start crispasr (chatterbox)

Error message

Failed to start crispasr (chatterbox)

What it means

Process.Start(psi) returned null, which on modern .NET essentially never happens for a real executable — it indicates the runtime/platform could not spawn a process at all. The engine throws InvalidOperationException naming the failure.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/ChatterboxTtsCpp.cs:593

            // and synth returns empty audio.
            psi.ArgumentList.Add("--codec-model");
            psi.ArgumentList.Add(GetS3GenModelPath(modelKey));
            psi.ArgumentList.Add("--host");
            psi.ArgumentList.Add("127.0.0.1");
            psi.ArgumentList.Add("--port");
            psi.ArgumentList.Add(port.ToString());
            // The crispasr server gates /v1/audio/speech requests with a `voice` field
            // behind --voice-dir being set ("warning: --voice-dir not set; … will reject
            // requests with a 'voice' field"). Pointing --voice-dir at our voices folder
            // satisfies the gate and also makes /v1/voices reflect the imported WAVs. It
            // does not make the chatterbox backend look the voice up in there though -
            // that is what the working directory above is for.
            psi.ArgumentList.Add("--voice-dir");
            psi.ArgumentList.Add(GetSetVoicesFolder());
            CrispAsrTtsProvenance.AddServerMarkingArgs(psi.ArgumentList, exe);

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

            // Record the exact launch command in the tools log so failures later in this
            // session can be reproduced from a shell. Also cache it on the static so the
            // runtime/startup error paths can surface it inline with the error dialog.
            var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);
            _serverLaunchCommand = launchCommand;
            Se.WriteToolsLog("Chatterbox TTS 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);

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Run outside any sandbox that blocks process spawning.
  2. Verify the exe path exists and (on POSIX) has the execute bit set.
  3. Check the runtime supports Process.Start on this platform.
  4. Capture and log psi.FileName / Arguments to reproduce manually.
Defensive patterns

Strategy: try-catch

Validate before calling

if (!File.Exists(exe)) return Invalid("exe missing: " + exe);
// nothing else to validate; Process.Start returning null is a host limitation

Try / catch

try { EnsureServerRunningAsync(modelKey, ct).Wait(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Failed to start crispasr"))
{ /* host cannot spawn processes; run outside the sandbox */ }

Prevention

When it happens

Trigger: Process.Start returns null rather than throwing — historically only on platforms/runtimes without a process-launch capability or in heavily sandboxed hosts.

Common situations: Running under a sandbox/container that blocks process creation; very old or non-standard runtime; execute permission missing on the binary on POSIX.

Related errors


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