{"record":{"id":"b6321f140847e916","repo":"SubtitleEdit/subtitleedit","slug":"failed-to-start-crispasr-omnivoice","errorCode":null,"errorMessage":"Failed to start crispasr (omnivoice)","messagePattern":"Failed to start crispasr \\(omnivoice\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs","lineNumber":639,"sourceCode":"            psi.ArgumentList.Add(\"--port\");\n            psi.ArgumentList.Add(port.ToString());\n            psi.ArgumentList.Add(\"--voice-dir\");\n            psi.ArgumentList.Add(GetSetVoicesFolder());\n            CrispAsrTtsProvenance.AddServerMarkingArgs(psi.ArgumentList, exe);\n\n            if (!string.IsNullOrEmpty(voicePath))\n            {\n                psi.ArgumentList.Add(\"--voice\");\n                psi.ArgumentList.Add(voicePath);\n                if (!string.IsNullOrEmpty(refText))\n                {\n                    psi.ArgumentList.Add(\"--ref-text\");\n                    psi.ArgumentList.Add(refText);\n                }\n            }\n\n            var process = Process.Start(psi)\n                ?? throw new InvalidOperationException(\"Failed to start crispasr (omnivoice)\");\n\n            var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);\n            _serverLaunchCommand = launchCommand;\n            Se.WriteToolsLog(\"OmniVoice (CrispASR) server starting — \"\n                + $\"PID: {process.Id}, \"\n                + $\"Cmd: {launchCommand}\");\n\n            lock (_serverLog) _serverLog.Clear();\n            process.ErrorDataReceived += (_, e) =>\n            {\n                if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);\n            };\n            process.OutputDataReceived += (_, e) =>\n            {\n                if (e.Data != null) lock (_serverLog) _serverLog.AppendLine(e.Data);\n            };\n            process.BeginErrorReadLine();\n            process.BeginOutputReadLine();","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs#L621-L657","documentation":"InvalidOperationException thrown if Process.Start(psi) returns null when launching the crispasr omnivoice server. As with error 243, this null-return path is practically unreachable because UseShellExecute is false — Process.Start either returns a Process or throws Win32Exception. The guard is purely defensive.","triggerScenarios":"Process.Start(psi) returns null. With the configured ProcessStartInfo (UseShellExecute=false), this does not occur in practice. A Win32Exception is the real failure mode when the binary cannot execute.","commonSituations":"Effectively unreachable in production. If observed, it points to a framework anomaly, a modified ProcessStartInfo, or a hypothetical future API change.","solutions":["Verify ProcessStartInfo.UseShellExecute is still false — if changed to true, this path becomes live.","If genuinely null, wrap in a try/catch for Win32Exception instead, since that is the realistic error.","Log the full psi state (FileName, Arguments, WorkingDirectory) to diagnose.","Retry once — a transient OS resource limit can occasionally cause process creation to fail."],"exampleFix":"// before\nvar process = Process.Start(psi)\n    ?? throw new InvalidOperationException(\"Failed to start crispasr (omnivoice)\");\n\n// after — handle the realistic exception types\nProcess process;\ntry { process = Process.Start(psi); }\ncatch (Win32Exception ex)\n{\n    throw new InvalidOperationException(\n        $\"Failed to start crispasr (omnivoice): {ex.Message}\", ex);\n}","handlingStrategy":"try-catch","validationCode":"// Verify binary exists before Process.Start\nvar exe = GetCrispAsrExecutable();\nif (!File.Exists(exe)) throw new FileNotFoundException(\"Missing: \" + exe, exe);","typeGuard":"null","tryCatchPattern":"catch (InvalidOperationException ex) when (ex.Message == \"Failed to start crispasr (omnivoice)\")\n{\n    Se.LogError(ex, \"Process.Start returned null unexpectedly.\");\n    throw;\n}","preventionTips":["This path is dead code with UseShellExecute=false; focus on Win32Exception.","Verify binary path and execute permissions before calling Process.Start.","Log the full ProcessStartInfo on failure for diagnosis."],"tags":["process","tts","omnivoice","crispasr","csharp","unreachable"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}