{"record":{"id":"f8016f8d29c5923b","repo":"microsoft/aspire","slug":"detached-unix-process-launch-requires-aspire-layout-services","errorCode":null,"errorMessage":"Detached Unix process launch requires Aspire layout services.","messagePattern":"Detached Unix process launch requires Aspire layout services\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/DotNet/ProcessExecution.cs","lineNumber":160,"sourceCode":"        {\n            detachedUnixLauncherLease?.Dispose();\n            _startCompletion.TrySetResult();\n        }\n\n        _logger.LogDebug(\"{FileName}({ProcessId}) started in {WorkingDirectory}\", _fileName, process.Id, _startInfo.WorkingDirectory);\n        return true;\n    }\n\n    private async Task<IDisposable?> ResolveDetachedUnixLauncherAsync(CancellationToken cancellationToken)\n    {\n        if (!_options.Detached || OperatingSystem.IsWindows() || _startInfo.DetachedUnixLauncherPath is not null)\n        {\n            return null;\n        }\n\n        if (_layoutDiscovery is null || _bundleService is null || _executionContext is null)\n        {\n            throw new InvalidOperationException(\"Detached Unix process launch requires Aspire layout services.\");\n        }\n\n        var dcpExecutable = await DcpExecutableResolver.TryGetDcpExecutableAsync(\n            _layoutDiscovery,\n            _bundleService,\n            _executionContext,\n            \"dcp-fork-process\",\n            cancellationToken).ConfigureAwait(false);\n        if (dcpExecutable is null)\n        {\n            throw new InvalidOperationException(\"Could not find DCP executable in the Aspire layout.\");\n        }\n\n        try\n        {\n            if (dcpExecutable.LayoutLease is not null)\n            {\n                var environment = _startInfo.Environment","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/DotNet/ProcessExecution.cs#L142-L178","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Run the detached launch only through the normal Aspire CLI startup so ILayoutDiscovery, IBundleService, and the execution context are registered and injected.","Register the missing service in the DI container before constructing ProcessExecution.","Fall back to non-detached (attached) process execution when layout services are unavailable.","In tests, provide fakes for all three dependencies instead of passing null."],"exampleFix":"// before\nvar executor = new ProcessExecution(null, null, null);\nawait executor.StartAsync(spec, detached: true);\n// after\nservices.AddAspireCliServices();\nvar executor = ActivatorUtilities.CreateInstance<ProcessExecution>(services.BuildServiceProvider());\nawait executor.StartAsync(spec, detached: true);","handlingStrategy":"validation","validationCode":"if (layoutDiscovery is null || bundleService is null || executionContext is null)\n{\n    throw new InvalidOperationException(\"Detached Unix launch requires layout services; use the CLI DI container.\");\n}","typeGuard":"bool canLaunchDetached = layoutDiscovery is not null && bundleService is not null && executionContext is not null;","tryCatchPattern":"try { await executor.StartAsync(spec, detached: true); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"layout services\"))\n{\n    logger.LogWarning(\"Falling back to attached execution: {Reason}\", ex.Message);\n    await executor.StartAsync(spec, detached: false);\n}","preventionTips":["Always construct ProcessExecution through the CLI DI container, not manually.","Fake all three layout dependencies in unit tests.","Fall back to attached execution when layout services are absent.","Add an assertion that required services resolve at startup."],"tags":["cli","process-launch","dependency-injection","unix"],"backgroundTag":"missing-dependency","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}