microsoft/aspire · error · InvalidOperationException

Failed to start child process

Error message

Failed to start child process: {startInfo.FileName}

What it means

StartRedirected launches a child via System.Diagnostics.Process.Start with redirected stdio. .NET's Process.Start returns null (rather than throwing) when the underlying CreateProcess call fails, and this code converts that null into an InvalidOperationException naming the executable. The most common underlying cause is the executable file not existing at the given path.

Solutions

  1. Verify startInfo.FileName exists and is executable: run `where <name>` (Windows) or `command -v <name>` (Unix) in the same environment.
  2. Use an absolute path for FileName instead of relying on PATH resolution.
  3. Confirm the WorkingDirectory exists and is accessible; a bad working directory fails spawn regardless of a valid FileName.
  4. Check PATH in the exact environment the CLI runs in (CI containers, VS Code terminals, services) and add the tool's directory.
  5. Install/repair the missing tool (e.g. run the Aspire CLI setup so dcp is provisioned).

Example fix

// before
startInfo.FileName = "dcp";
// after
startInfo.FileName = "/home/user/.aspire/bin/dcp/dcp"; // resolved absolute path
// (or ensure the directory containing the executable is on PATH before starting)
Defensive patterns

Strategy: validation

Validate before calling

// Validate the executable and working directory before Start
var exePath = ResolveExecutable(fileName); // search PATH or use absolute path
if (exePath is null || !File.Exists(exePath))
{
    throw new FileNotFoundException($"Executable '{fileName}' was not found. Install it or add its directory to PATH.");
}
if (workingDirectory is not null && !Directory.Exists(workingDirectory))
{
    throw new DirectoryNotFoundException($"Working directory '{workingDirectory}' does not exist.");
}

Try / catch

try
{
    var process = isolatedProcess.Start(startInfo);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Failed to start child process:"))
{
    // FileName didn't resolve — verify PATH / installation before retrying
}

Prevention

When it happens

Trigger: StartAsync routes to StartRedirected (non-detached, redirected stdio path), Process.Start(psi) returns null for startInfo.FileName — typically because FileName doesn't resolve (bad path, missing extension, not on PATH) or the working directory is invalid.

Common situations: Typing a wrong executable name/path in apphost configuration, a tool (dcp, dotnet, docker) not installed or not on PATH, running the CLI from a directory where a relative WorkingDirectory no longer exists, or a PATH stripped in CI containers.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/cb2f9f198becdf58. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Processes/IsolatedProcess.cs:396

            // Pin encodings so process output decoding is stable regardless of the ambient
            // Console.OutputEncoding (e.g. on container hosts that leave it set to ASCII).
            StandardOutputEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false),
            StandardErrorEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false),
        };

        foreach (var arg in startInfo.ArgumentList)
        {
            psi.ArgumentList.Add(arg);
        }

        // Only mutate the ProcessStartInfo env block when the caller actually touched
        // IsolatedProcessStartInfo.Environment. Otherwise leave ProcessStartInfo to inherit
        // the parent's env verbatim — saves a snapshot-and-copy round trip for the common
        // case where nothing was customized.
        ProcessEnvironment.ApplyTo(psi, startInfo.GetEnvironmentForSpawn());

        var process = Process.Start(psi)
            ?? throw new InvalidOperationException($"Failed to start child process: {startInfo.FileName}");

        process.StandardInput.Close();

        return new StartedProcess(
            process,
            process.StandardOutput,
            process.StandardError,
            ExtraDispose: null);
    }

    /// <summary>
    /// Applies the already-started process and platform-specific handle/readers to this wrapper.
    /// </summary>
    private void InitializeStartedProcess(StartedProcess startedProcess)
    {
        _process = startedProcess.Process;
        _id = startedProcess.ProcessId ?? startedProcess.Process.Id;
        Arguments = _startInfo.ArgumentList.ToArray();

View on GitHub (pinned to 25830f84bd)