stride3d/stride · error · InvalidOperationException
Process [ ] couldn't start
Error message
Process [{command}] couldn't start What it means
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.
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.
Example fix
// before
await ShellHelper.RunProcessAndGetOutputAsync("dotnet-stride restore", ...);
// after
var dotnet = "dotnet"; // ensure resolved: which dotnet / where dotnet
await ShellHelper.RunProcessAndGetOutputAsync($"{dotnet} tool restore", ...); Defensive patterns
Strategy: validation
Validate before calling
static void ValidateCommandRunnable(string command)
{
var exe = command.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0];
var resolved = Environment.OSVersion.Platform == PlatformID.Win32NT
? FindOnPath(exe + ".exe") ?? FindOnPath(exe)
: FindOnPath(exe);
if (resolved == null) throw new InvalidOperationException($"Executable '{exe}' not found on PATH.");
if (!OperatingSystem.IsWindows() && !HasExecuteBit(resolved)) throw new InvalidOperationException($"'{resolved}' is not executable (chmod +x needed).");
} Type guard
static bool IsExecutableFilePresent(string path) =>
File.Exists(path) &&
(OperatingSystem.IsWindows() ||
(File.GetUnixFileMode(path) & UnixFileMode.OtherExecute) != 0); Try / catch
try
{
var code = await ShellHelper.RunProcessAndGetOutputAsync(command, logger, ct);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Process ["))
{
logger.Error($"Failed to spawn '{command}'. Check path, execute bit, and PATH.");
throw;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Could not start install package process
- Error code while running install package process [ ]
- git exited with
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/11b359e192555e2c.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shared/Stride.Core.ShellHelper/ShellHelper.cs:37
/// <param name="parameters">The parameters of the command.</param>
/// <returns>The outputs.</returns>
public static async Task<int> RunProcessAndGetOutputAsync(string command, string parameters, ILogger logger, CancellationToken cancellationToken = default(CancellationToken))
{
using var process = new Process
{
StartInfo = new ProcessStartInfo(command, parameters)
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
}
};
process.OutputDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { logger.Verbose(args.Data); } };
process.ErrorDataReceived += (_, args) => { if (!string.IsNullOrEmpty(args.Data)) { logger.Error(args.Data); } };
if (!process.Start())
throw new InvalidOperationException($"Process [{command}] couldn't start");
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
return process.ExitCode;
}
/// <summary>
/// Run the process and get the output without deadlocks.
/// </summary>
/// <param name="command">The name or path of the command.</param>
/// <param name="parameters">The parameters of the command.</param>
/// <returns>The outputs.</returns>
public static ProcessOutputs RunProcessAndGetOutput(string command, string parameters)
{
var outputs = new ProcessOutputs();
using (var process = Process.Start(View on GitHub (pinned to 96fad776d2)