SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to start omnivoice-tts

Error message

Failed to start omnivoice-tts

What it means

InvalidOperationException thrown if Process.Start(psi) returns null when launching the omnivoice-tts CLI for a single synthesis. As with errors 243 and 250, this null path is practically unreachable with UseShellExecute=false; the realistic failure is a Win32Exception when the binary cannot execute.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceTtsCpp.cs:323

            psi.ArgumentList.Add(refTextPath);
        }

        // Voice-design keywords (--instruct) only shape the voice when there is no reference
        // audio - with --ref-wav omnivoice-tts takes the voice from the clone and ignores them.
        if (!usingReference)
        {
            var instruction = (Se.Settings.Video.TextToSpeech.OmniVoiceTtsCppInstruction ?? string.Empty).Trim();
            if (!string.IsNullOrEmpty(instruction))
            {
                psi.ArgumentList.Add("--instruct");
                psi.ArgumentList.Add(instruction);
            }
        }

        Se.WriteToolsLog($"OmniVoice TTS: {exe} {string.Join(' ', psi.ArgumentList)} (voice={omniVoice}, textLen={text.Length})");

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

        try
        {
            var stderrTask = process.StandardError.ReadToEndAsync(cancellationToken);
            var stdoutTask = process.StandardOutput.ReadToEndAsync(cancellationToken);

            await process.StandardInput.WriteAsync(inputText.AsMemory(), cancellationToken);
            process.StandardInput.Close();

            await process.WaitForExitAsync(cancellationToken);
            var stderr = await stderrTask;
            var stdout = await stdoutTask;

            if (process.ExitCode != 0 || !File.Exists(outputFileName))
            {
                // A process killed by the Windows loader (e.g. missing CUDA runtime, issue #13196)
                // never reaches main, so stderr is empty and the bare exit code is all the user sees.
                // NativeExitCodeHelper turns the known status codes into an actionable sentence.

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Verify ProcessStartInfo.UseShellExecute is false.
  2. If the binary genuinely won't start, the real error is a Win32Exception — wrap Process.Start in try/catch(Win32Exception) for a useful message.
  3. Confirm the executable is not blocked (Windows Mark-of-the-Web) or quarantined.
  4. Check execute permissions on Linux/macOS (chmod +x).

Example fix

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

// after — catch the real failure mode
try { var process = Process.Start(psi); }
catch (Win32Exception ex) when (ex.NativeErrorCode == 5)
{
    throw new InvalidOperationException("omnivoice-tts is not executable. Run chmod +x.", ex);
}
catch (Win32Exception ex)
{
    throw new InvalidOperationException($"Failed to start omnivoice-tts: {ex.Message}", ex);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify binary exists and is executable
var exe = GetExecutableFileName();
if (!File.Exists(exe)) throw new FileNotFoundException("Missing: " + exe, exe);

Type guard

null

Try / catch

catch (InvalidOperationException ex) when (ex.Message == "Failed to start omnivoice-tts")
{
    Se.LogError(ex, "Process.Start returned null unexpectedly.");
    throw;
}

Prevention

When it happens

Trigger: Process.Start(psi) returns null. With UseShellExecute=false, Process.Start throws rather than returning null. This guard is defensive dead code under the current configuration.

Common situations: Unreachable in production. If observed, check whether UseShellExecute was changed, or whether a framework-level issue caused a null return.

Related errors


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