microsoft/aspire · error · InvalidOperationException
DCP fork-process did not return a child process ID. DCP…
Error message
DCP fork-process did not return a child process ID. DCP fork-process exited with code {dcpProcess.ExitCode}. stderr: '{stderr.Trim()}' What it means
The DCP fork-process contract is to print exactly the detached child's PID on stdout followed by a newline. When stdout ends without a line (stream closed), the launcher exited without producing a child PID, so StartDetachedUnixAsync waits for exit and throws with the exit code and captured stderr to expose the underlying DCP failure. Without a PID the caller cannot manage the detached child.
Solutions
- Read the stderr embedded in the exception message — it contains the actual DCP error — and fix that root cause first.
- Clear stale DCP state/cache directories and retry the operation.
- Update the Aspire CLI (and bundled DCP) so versions are compatible.
- Run the DCP launcher manually with the same arguments/environment to reproduce its failure and inspect its output.
- Check disk space, permissions, and ports if stderr indicates resource constraints.
Example fix
// before: retrying blindly without reading stderr
// after: capture and act on the embedded stderr
try
{
var started = await isolatedProcess.StartAsync(ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("DCP fork-process"))
{
logger.LogError(ex, "DCP launcher failed; check embedded stderr for root cause");
throw;
} Defensive patterns
Strategy: try-catch
Try / catch
try
{
var started = await process.StartAsync(ct);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("DCP fork-process did not return"))
{
// parse exit code and stderr from the message; fix the DCP root cause before retrying
logger.LogError(ex, "DCP launcher exited without a child PID");
} Prevention
- Read the embedded stderr in the message before retrying
- Keep CLI and DCP versions matched
- Clear stale DCP state directories after failed runs
- Ensure the app process being forked starts successfully on its own
When it happens
Trigger: During StartAsync detached Unix launch, the DCP launcher process exits (any non-zero or even zero without printing a PID) before writing a PID line, e.g. DCP config errors, port/resource failures, or DCP crash on startup.
Common situations: Corrupt or stale DCP state directory; DCP failing to bind its socket; incompatible DCP version with the CLI; the inner app process failing immediately so the launcher aborts.
Related errors
- DCP fork-process did not return a valid child process ID…
- Failed to start DCP fork-process.
- Unix detached process launch requires a DCP executable path.
- Could not determine the identity timestamp for monitor…
- Could not find DCP executable in the Aspire layout.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/814a2a09f51dbb0b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Cli/Processes/IsolatedProcess.Unix.cs:62
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:
// 12345
if (!int.TryParse(trimmedStdout, NumberStyles.None, CultureInfo.InvariantCulture, out var childPid))
{
throw new InvalidOperationException($"DCP fork-process did not return a valid child process ID. stdout: '{trimmedStdout}'");
}
ObserveDcpForkProcessStderr(stderrTask);
Process? childProcess;
try
{
childProcess = Process.GetProcessById(childPid);
}
catch (ArgumentException)View on GitHub (pinned to 25830f84bd)