{"record":{"id":"5b839c9bc9bd97a4","repo":"SubtitleEdit/subtitleedit","slug":"failed-to-start-crispasr-moss-tts","errorCode":null,"errorMessage":"Failed to start crispasr (moss-tts)","messagePattern":"Failed to start crispasr \\(moss-tts\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/MossTtsCrispAsr.cs","lineNumber":701,"sourceCode":"            if (!string.IsNullOrEmpty(languageArg))\n            {\n                psi.ArgumentList.Add(\"-l\");\n                psi.ArgumentList.Add(languageArg);\n            }\n\n            if (UseStartupVoiceFlags)\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 (moss-tts)\");\n\n            var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);\n            _serverLaunchCommand = launchCommand;\n            Se.WriteToolsLog(\"MOSS-TTS (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":683,"sourceCodeEnd":719,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/MossTtsCrispAsr.cs#L683-L719","documentation":"InvalidOperationException thrown if Process.Start(psi) returns null. In practice this is nearly unreachable: with UseShellExecute=false (as configured here), Process.Start either returns a non-null Process object or throws a Win32Exception. The null-check is a defensive guard for the theoretical shell-execute case or a future framework change.","triggerScenarios":"Process.Start(psi) returns null. Given UseShellExecute=false in the ProcessStartInfo, the only realistic path is a CLR/framework edge case or a future API change. Under normal conditions, if the binary cannot start, a Win32Exception (not null) is thrown instead.","commonSituations":"Essentially unreachable in production with the current ProcessStartInfo configuration. If it does surface, it indicates a CLR bug, a broken Process.Start shim, or code that was refactored to set UseShellExecute=true without updating this guard.","solutions":["Check whether the ProcessStartInfo.UseShellExecute flag was inadvertently changed to true — with false, this throw path is dead code.","If genuinely null from the framework, file a dotnet/runtime issue and temporarily retry the Process.Start call.","Verify the executable path and arguments are valid (a bad FileName throws Win32Exception, not null, but sanity-check anyway).","Log the psi contents to Tools log to capture the exact state at the time of failure for diagnosis."],"exampleFix":"// before — defensive null-coalesce that is practically dead code\nvar process = Process.Start(psi)\n    ?? throw new InvalidOperationException(\"Failed to start crispasr (moss-tts)\");\n\n// after — catch the actual failure modes (Win32Exception) instead\ntry { var process = Process.Start(psi); }\ncatch (Win32Exception ex)\n{\n    throw new InvalidOperationException(\n        $\"Failed to start crispasr (moss-tts): {ex.Message}. \" +\n        \"Check the executable exists and is not blocked.\", ex);\n}","handlingStrategy":"try-catch","validationCode":"// Verify the binary exists and is executable 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 (moss-tts)\")\n{\n    // Practically unreachable; the real error is Win32Exception.\n    // Log the psi state and fall through to a generic handler.\n    Se.LogError(ex, \"Process.Start returned null unexpectedly.\");\n    throw;\n}","preventionTips":["This path is dead code with UseShellExecute=false; focus on Win32Exception instead.","Verify the binary path and execute permissions before calling Process.Start.","Log the full ProcessStartInfo contents on failure for diagnosis."],"tags":["process","tts","moss-tts","crispasr","csharp","unreachable"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}