microsoft/aspire · error · InvalidOperationException

Detached Unix process launch requires Aspire layout…

Error message

Detached Unix process launch requires Aspire layout services.

What it means

The Aspire CLI can launch detached (daemonized) Unix processes only through the DCP 'dcp-fork-process' helper that ships inside an Aspire layout. ResolveDetachedUnixLauncherAsync checks that the layout discovery, bundle service, and execution context services were all injected; if any is null the detached-launch path cannot work and this InvalidOperationException is thrown instead of silently mis-launching the process.

Solutions

  1. Run the detached launch only through the normal Aspire CLI startup so ILayoutDiscovery, IBundleService, and the execution context are registered and injected.
  2. Register the missing service in the DI container before constructing ProcessExecution.
  3. Fall back to non-detached (attached) process execution when layout services are unavailable.
  4. In tests, provide fakes for all three dependencies instead of passing null.

Example fix

// before
var executor = new ProcessExecution(null, null, null);
await executor.StartAsync(spec, detached: true);
// after
services.AddAspireCliServices();
var executor = ActivatorUtilities.CreateInstance<ProcessExecution>(services.BuildServiceProvider());
await executor.StartAsync(spec, detached: true);
Defensive patterns

Strategy: validation

Validate before calling

if (layoutDiscovery is null || bundleService is null || executionContext is null)
{
    throw new InvalidOperationException("Detached Unix launch requires layout services; use the CLI DI container.");
}

Type guard

bool canLaunchDetached = layoutDiscovery is not null && bundleService is not null && executionContext is not null;

Try / catch

try { await executor.StartAsync(spec, detached: true); }
catch (InvalidOperationException ex) when (ex.Message.Contains("layout services"))
{
    logger.LogWarning("Falling back to attached execution: {Reason}", ex.Message);
    await executor.StartAsync(spec, detached: false);
}

Prevention

When it happens

Trigger: Calling StartAsync with detached Unix process launch enabled while ILayoutDiscovery, IBundleService, or the execution context dependency on ProcessExecution is null (e.g. ProcessExecution constructed manually or used outside the normal CLI DI composition).

Common situations: Embedding or unit-testing ProcessExecution directly without the full CLI service graph; running the detached launch path in an environment where layout services were never initialized; a DI registration change leaving one of the three services unbound.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/DotNet/ProcessExecution.cs:160

        {
            detachedUnixLauncherLease?.Dispose();
            _startCompletion.TrySetResult();
        }

        _logger.LogDebug("{FileName}({ProcessId}) started in {WorkingDirectory}", _fileName, process.Id, _startInfo.WorkingDirectory);
        return true;
    }

    private async Task<IDisposable?> ResolveDetachedUnixLauncherAsync(CancellationToken cancellationToken)
    {
        if (!_options.Detached || OperatingSystem.IsWindows() || _startInfo.DetachedUnixLauncherPath is not null)
        {
            return null;
        }

        if (_layoutDiscovery is null || _bundleService is null || _executionContext is null)
        {
            throw new InvalidOperationException("Detached Unix process launch requires Aspire layout services.");
        }

        var dcpExecutable = await DcpExecutableResolver.TryGetDcpExecutableAsync(
            _layoutDiscovery,
            _bundleService,
            _executionContext,
            "dcp-fork-process",
            cancellationToken).ConfigureAwait(false);
        if (dcpExecutable is null)
        {
            throw new InvalidOperationException("Could not find DCP executable in the Aspire layout.");
        }

        try
        {
            if (dcpExecutable.LayoutLease is not null)
            {
                var environment = _startInfo.Environment

View on GitHub (pinned to 25830f84bd)