{"record":{"id":"637a165c66fc7f8a","repo":"SubtitleEdit/subtitleedit","slug":"failed-to-start-crispasr-qwen3-tts","errorCode":null,"errorMessage":"Failed to start crispasr (qwen3-tts)","messagePattern":"Failed to start crispasr \\(qwen3-tts\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs","lineNumber":986,"sourceCode":"                psi.ArgumentList.Add(codec);\n            }\n            if (!hasLocalTalker || !hasLocalCodec)\n            {\n                psi.ArgumentList.Add(\"--auto-download\");\n            }\n            psi.ArgumentList.Add(\"--host\");\n            psi.ArgumentList.Add(\"127.0.0.1\");\n            psi.ArgumentList.Add(\"--port\");\n            psi.ArgumentList.Add(port.ToString());\n            // The crispasr server gates /v1/audio/speech requests with a `voice` field behind\n            // --voice-dir being set. Pointing at our voices folder satisfies the gate and also\n            // makes /v1/voices reflect any imported reference WAVs.\n            psi.ArgumentList.Add(\"--voice-dir\");\n            psi.ArgumentList.Add(GetSetVoicesFolder());\n            CrispAsrTtsProvenance.AddServerMarkingArgs(psi.ArgumentList, exe);\n\n            var process = Process.Start(psi)\n                ?? throw new InvalidOperationException(\"Failed to start crispasr (qwen3-tts)\");\n\n            var launchCommand = FormatLaunchCommand(exe, psi.ArgumentList);\n            _serverLaunchCommand = launchCommand;\n            Se.WriteToolsLog(\"Qwen3 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":968,"sourceCodeEnd":1004,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs#L968-L1004","documentation":"Defensive InvalidOperationException thrown when Process.Start(psi) returns null while launching crispasr. As with the qwen3-tts equivalent, UseShellExecute is false here so Start should throw rather than return null in normal operation; this guard catches a runtime/platform quirk that yields null instead.","triggerScenarios":"A future change sets UseShellExecute=true; a host runtime that returns null for an empty/invalid argument list instead of throwing; an exotic sandboxed environment that partially virtualises process creation.","commonSituations":"Code regression flipping UseShellExecute; unusual container/jail setups; effectively unreachable on normal desktop runtimes.","solutions":["Confirm UseShellExecute stays false in the launch path.","Reproduce the ProcessStartInfo in a standalone harness to see whether Start returns null or throws a real exception.","If isolated to a sandbox, relax its process-creation policy.","Treat as a defect on normal desktops — file a bug; Start is expected to throw, not return null."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (psi.UseShellExecute)\n    throw new InvalidOperationException(\"UseShellExecute must be false.\");\nif (string.IsNullOrWhiteSpace(psi.FileName))\n    throw new InvalidOperationException(\"Executable path is empty.\");","typeGuard":null,"tryCatchPattern":"try { var process = Process.Start(psi) ?? throw new InvalidOperationException(\"Failed to start crispasr (qwen3-tts)\"); }\ncatch (System.ComponentModel.Win32Exception ex) { Se.LogError(ex); throw; }","preventionTips":["Keep UseShellExecute=false.","Log the full launch command before Start.","Treat a null return as a defect — investigate the runtime/sandbox."],"tags":["tts","crispasr","process-start","defensive","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}