SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to start kokoro-tts-server

Error message

Failed to start kokoro-tts-server

What it means

InvalidOperationException from KokoroTtsCpp.EnsureServerRunningAsync when `Process.Start(psi)` returns null. As with the other engines, modern .NET throws on spawn failure rather than returning null, so this is a defensive guard that is rarely hit in practice. If reached, the OS declined to spawn the configured kokoro-tts-server with the built argument list without a thrown exception.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/KokoroTtsCpp.cs:331

                // (relative path baked into the binary's default --vocab arg).
                WorkingDirectory = GetSetFolder(),
                FileName = exe,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
            };
            psi.ArgumentList.Add("-m");
            psi.ArgumentList.Add(modelPath);
            psi.ArgumentList.Add("-V");
            psi.ArgumentList.Add(voicesPath);
            psi.ArgumentList.Add("--host");
            psi.ArgumentList.Add("127.0.0.1");
            psi.ArgumentList.Add("--port");
            psi.ArgumentList.Add(port.ToString());

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

            Se.WriteToolsLog($"Kokoro TTS server starting - PID: {process.Id}, "
                + $"Cmd: {exe} {string.Join(' ', psi.ArgumentList)}");

            var stderrBuffer = new StringBuilder();
            process.ErrorDataReceived += (_, e) =>
            {
                if (e.Data != null) lock (stderrBuffer) stderrBuffer.AppendLine(e.Data);
            };
            process.OutputDataReceived += (_, e) =>
            {
                if (e.Data != null) lock (stderrBuffer) stderrBuffer.AppendLine(e.Data);
            };
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            _serverProcess = process;
            _serverPort = port;

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Treat as 'spawn failed for unknown reason' — verify the exe path and permissions.
  2. Run the exact command logged just after this throw by hand to surface the OS error.
  3. Confirm GetExecutableFileName() is valid and executable.
  4. Update the runtime if a genuine null return occurs.
Defensive patterns

Strategy: try-catch

Validate before calling

if (!File.Exists(exe)) throw new FileNotFoundException("kokoro exe missing", exe);

Try / catch

try { await kokoroEngine.Speak(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Failed to start kokoro-tts-server"))
{
    ShowLaunchCommand(ex.Message); // reproduce manually
}

Prevention

When it happens

Trigger: Effectively unreachable on current .NET; the realistic failures (missing exe → FileNotFoundException; permission/path issues → Win32Exception) throw before this line.

Common situations: Observed only on runtimes/shims returning null; otherwise a dead branch.

Related errors


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