{"record":{"id":"11b359e192555e2c","repo":"stride3d/stride","slug":"process-command-couldn-t-start","errorCode":null,"errorMessage":"Process [{command}] couldn't start","messagePattern":"Process \\[(.+?)\\] couldn't start","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shared/Stride.Core.ShellHelper/ShellHelper.cs","lineNumber":37,"sourceCode":"        /// <param name=\"parameters\">The parameters of the command.</param>\n        /// <returns>The outputs.</returns>\n        public static async Task<int> RunProcessAndGetOutputAsync(string command, string parameters, ILogger logger, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            using var process = new Process\n            {\n                StartInfo = new ProcessStartInfo(command, parameters)\n                {\n                    UseShellExecute = false,\n                    CreateNoWindow = true,\n                    RedirectStandardError = true,\n                    RedirectStandardOutput = true,\n                }\n            };\n            process.OutputDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { logger.Verbose(args.Data); } };\n            process.ErrorDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { logger.Error(args.Data); } };\n\n            if (!process.Start())\n                throw new InvalidOperationException($\"Process [{command}] couldn't start\");\n\n            process.BeginOutputReadLine();\n            process.BeginErrorReadLine();\n\n            await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);\n            return process.ExitCode;\n        }\n\n        /// <summary>\n        /// Run the process and get the output without deadlocks.\n        /// </summary>\n        /// <param name=\"command\">The name or path of the command.</param>\n        /// <param name=\"parameters\">The parameters of the command.</param>\n        /// <returns>The outputs.</returns>\n        public static ProcessOutputs RunProcessAndGetOutput(string command, string parameters)\n        {\n            var outputs = new ProcessOutputs();\n            using (var process = Process.Start(","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shared/Stride.Core.ShellHelper/ShellHelper.cs#L19-L55","documentation":"ShellHelper.RunProcessAndGetOutputAsync starts an external process via Process.Start; Process.Start returns false when the OS fails to launch the process (it does not always throw). The helper surfaces that as an InvalidOperationException with the full command line. It indicates the command could not be spawned at all, before any output or exit code exists.","triggerScenarios":"Calling RunProcessAndGetOutputAsync with a command string whose executable cannot be launched: nonexistent binary, non-executable file, or an environment where CreateProcess/fork fails; Process.Start() returns false.","commonSituations":"Tool path wrong or not installed; running on Linux/macOS where the file lacks the execute bit; PATH missing the binary; sandboxed CI environments blocking process spawn.","solutions":["Confirm the executable path in the command exists and is runnable (which <cmd> / Test-Path).","On Unix, chmod +x the binary or ship it with the execute bit set.","Run the command directly in a shell to see the underlying OS error.","If relying on PATH, use the resolved absolute path instead."],"exampleFix":"// before\nawait ShellHelper.RunProcessAndGetOutputAsync(\"dotnet-stride restore\", ...);\n// after\nvar dotnet = \"dotnet\"; // ensure resolved: which dotnet / where dotnet\nawait ShellHelper.RunProcessAndGetOutputAsync($\"{dotnet} tool restore\", ...);","handlingStrategy":"validation","validationCode":"static void ValidateCommandRunnable(string command)\n{\n    var exe = command.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0];\n    var resolved = Environment.OSVersion.Platform == PlatformID.Win32NT\n        ? FindOnPath(exe + \".exe\") ?? FindOnPath(exe)\n        : FindOnPath(exe);\n    if (resolved == null) throw new InvalidOperationException($\"Executable '{exe}' not found on PATH.\");\n    if (!OperatingSystem.IsWindows() && !HasExecuteBit(resolved)) throw new InvalidOperationException($\"'{resolved}' is not executable (chmod +x needed).\");\n}","typeGuard":"static bool IsExecutableFilePresent(string path) =>\n    File.Exists(path) &&\n    (OperatingSystem.IsWindows() ||\n     (File.GetUnixFileMode(path) & UnixFileMode.OtherExecute) != 0);","tryCatchPattern":"try\n{\n    var code = await ShellHelper.RunProcessAndGetOutputAsync(command, logger, ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Process [\"))\n{\n    logger.Error($\"Failed to spawn '{command}'. Check path, execute bit, and PATH.\");\n    throw;\n}","preventionTips":["Resolve tools to absolute paths instead of relying on PATH.","On Unix, ship executables with the execute bit and verify in packaging scripts.","Run each external command once in a shell during environment setup to catch missing tools early."],"tags":["process","shell","process-start-failed"],"backgroundTag":"command-not-found","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}