microsoft/aspire · error · InvalidOperationException

Failed to start DCP fork-process.

Error message

Failed to start DCP fork-process.

What it means

After building the DCP ProcessStartInfo, StartDetachedUnixAsync calls Process.Start and throws if the OS returns null, meaning the DCP fork-process could not be launched at all. This indicates a pre-exec failure (bad path, missing binary, exec permissions) rather than a runtime error from DCP itself.

Solutions

  1. Verify the DCP path exists and is executable (ls -l $path; chmod +x $path).
  2. Reinstall/repair the Aspire CLI to restore a complete DCP binary for your platform/arch.
  3. Run the DCP binary directly in a terminal to see the OS-level error.
  4. Check CPU architecture matches the binary (file $path on Linux/macOS).

Example fix

// before: launcher binary present but not executable
// after
chmod +x /path/to/dcp
var dcpProcess = Process.Start(dcpStartInfo)
    ?? throw new InvalidOperationException("Failed to start DCP fork-process.");
Defensive patterns

Strategy: validation

Validate before calling

var path = startInfo.DetachedUnixLauncherPath!;
if (!File.Exists(path)) throw new FileNotFoundException("DCP launcher not found", path);
if (!(File.GetUnixFileMode(path) & UnixFileMode.Execute).HasFlag(UnixFileMode.Execute))
    throw new UnauthorizedAccessException($"DCP launcher is not executable: {path}");

Try / catch

try
{
    await process.StartAsync(ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Failed to start DCP fork-process"))
{
    // check launcher exists, is executable, and matches the machine architecture
}

Prevention

When it happens

Trigger: Process.Start(dcpStartInfo) returns null during StartAsync's detached Unix launch: DetachedUnixLauncherPath points to a nonexistent, non-executable, or incompatible (wrong arch/OS) binary.

Common situations: A truncated or partially extracted DCP binary after an interrupted install; wrong-architecture binary (arm64 vs x64); file lacks +x permission; path corrupted after an upgrade.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/Processes/IsolatedProcess.Unix.cs:48

        dcpStartInfo.ArgumentList.Add("fork-process");
        dcpStartInfo.ArgumentList.Add("--monitor");
        dcpStartInfo.ArgumentList.Add(Environment.ProcessId.ToString(CultureInfo.InvariantCulture));
        dcpStartInfo.ArgumentList.Add("--monitor-identity-time");
        dcpStartInfo.ArgumentList.Add(ProcessTreeGracefulShutdownService.FormatDcpProcessStartTime(GetCurrentProcessDcpMonitorStartTime()));
        dcpStartInfo.ArgumentList.Add("--");
        dcpStartInfo.ArgumentList.Add(startInfo.FileName);
        foreach (var arg in startInfo.ArgumentList)
        {
            dcpStartInfo.ArgumentList.Add(arg);
        }

        ProcessEnvironment.ApplyTo(dcpStartInfo, startInfo.GetEnvironmentForSpawn());

        cancellationToken.ThrowIfCancellationRequested();

        var dcpProcess = Process.Start(dcpStartInfo)
            ?? throw new InvalidOperationException("Failed to start DCP fork-process.");

        var stderrTask = dcpProcess.StandardError.ReadToEndAsync(CancellationToken.None);
        var stdoutLineTask = dcpProcess.StandardOutput.ReadLineAsync(CancellationToken.None).AsTask();

        try
        {
            // Once DCP has started, wait for it to report the detached child PID even if the caller
            // cancels. Without the PID, callers cannot clean up a child that was already forked.
            var stdoutLine = await stdoutLineTask.ConfigureAwait(false);
            if (stdoutLine is null)
            {
                await dcpProcess.WaitForExitAsync(CancellationToken.None).ConfigureAwait(false);
                var stderr = await stderrTask.ConfigureAwait(false);
                throw new InvalidOperationException($"DCP fork-process did not return a child process ID. DCP fork-process exited with code {dcpProcess.ExitCode}. stderr: '{stderr.Trim()}'");
            }

            var trimmedStdout = stdoutLine.Trim();
            // DCP fork-process writes only the detached child PID followed by a newline, for example:

View on GitHub (pinned to 25830f84bd)