microsoft/aspire · error · InvalidOperationException

Run completed without returning a backchannel.

Error message

Run completed without returning a backchannel.

What it means

PipelineCommandBase awaits a backchannelCompletionSource that the running AppHost task must complete with an auxiliary backchannel. If the run task completes (successfully or faulted) without ever setting a backchannel, ExecuteAsync throws InvalidOperationException, including the run task's exception as InnerException when it faulted.

Solutions

  1. Check the InnerException / AppHost run output for the underlying startup failure and fix it
  2. Update the AppHost's Aspire.Hosting packages so it establishes the backchannel (see the related --list-steps incompatibility)
  3. Rerun 'aspire pipeline' after the AppHost starts successfully; add a hangdump/timeout to diagnose stalls

Example fix

// before
aspire pipeline ./MyApp.AppHost/MyApp.AppHost.csproj
// after
dotnet run --project MyApp.AppHost   # first verify the AppHost starts and stays running
aspire pipeline ./MyApp.AppHost/MyApp.AppHost.csproj
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the AppHost starts and stays up before running pipelines
dotnet run --project MyApp.AppHost & sleep 10
kill %1  # only proceed if startup output showed no errors

Try / catch

try
{
    await pipeline.ExecuteAsync(...);
}
catch (InvalidOperationException ex) when (ex.Message == "Run completed without returning a backchannel.")
{
    Console.Error.WriteLine($"AppHost run failed before backchannel setup: {ex.InnerException?.Message}");
    throw ex.InnerException ?? ex;
}

Prevention

When it happens

Trigger: The AppHost run task finished without publishing a backchannel — the AppHost exited before establishing the auxiliary backchannel, the hosted run failed (faulted task), or an older AppHost never wires the backchannel completion.

Common situations: 'aspire pipeline' against an AppHost that crashes on startup or exits immediately; AppHost version too old to return a backchannel; run cancelled before the backchannel handshake completed.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/Commands/PipelineCommandBase.cs:322

                if (completedTask.IsFaulted && completedTask.Exception?.InnerException is DotNetSdkNotInstalledException sdkException)
                {
                    throw sdkException;
                }

                // When running in extension context, the extension takes over apphost management.
                // DotNetCliRunner returns Success immediately after delegating to LaunchAppHostAsync,
                // so pendingRun completes before the backchannel is established. In this case,
                // continue waiting for the backchannel rather than throwing.
                if (!completedTask.IsFaulted && await pendingRun == CliExitCodes.Success
                    && ExtensionHelper.IsExtensionHost(InteractionService, out _, out _))
                {
                    return await backchannelCompletionSource.Task;
                }

                // Throw an error if the run completed without returning a backchannel.
                // Include possible error if the run task faulted.
                var innerException = completedTask.IsFaulted ? completedTask.Exception : null;
                throw new InvalidOperationException("Run completed without returning a backchannel.", innerException);
            }), emoji: KnownEmojis.HammerAndWrench);

            // If --list-steps was specified, get pipeline steps and print them instead of executing
            if (listSteps)
            {
                StopTerminalProgressBar();
                int inspectionExitCode;

                try
                {
                    // Check that the AppHost supports this capability before calling
                    var capabilities = await backchannel.GetCapabilitiesAsync(cancellationToken);
                    if (!capabilities.Contains(ListStepsCapability))
                    {
                        throw new AppHostIncompatibleException(
                            ListStepsIncompatibleMessage,
                            ListStepsCapability);
                    }

View on GitHub (pinned to 25830f84bd)