microsoft/aspire · error · InvalidOperationException

Already connected to

Error message

Already connected to {Name} backchannel.

What it means

ConnectAsync on ExtensionBackchannel tracks connection state via _rpcTaskCompletionSource. If the RPC task is already completed (a connection exists), calling ConnectAsync again throws this InvalidOperationException — the backchannel is designed for a single connection to the extension, not repeated connects.

Solutions

  1. Do not call ConnectAsync if already connected; check the connected state (or wrap in try/catch for InvalidOperationException) before connecting.
  2. Call ConnectAsync once during initialization and rely on subsequent helper methods to reuse the existing connection.
  3. If a reconnection is genuinely needed, dispose/reset the backchannel instance before connecting again.

Example fix

// before
await backchannel.ConnectAsync(endpoint, cancellationToken);
await backchannel.ConnectAsync(endpoint, cancellationToken); // throws

// after
if (Volatile.Read(ref backchannel._connected) == 0)
{
    await backchannel.ConnectAsync(endpoint, cancellationToken);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (backchannel.IsConnected) return; // skip redundant ConnectAsync

Type guard

bool shouldConnect = !backchannel.IsConnected;

Try / catch

try { await backchannel.ConnectAsync(endpoint, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Already connected"))
{ /* ignore: connection already established */ }

Prevention

When it happens

Trigger: Calling ConnectAsync (directly or indirectly through DisplayMessageAsync, DisplaySuccessAsync, DisplaySubtleMessageAsync, DisplayErrorAsync, DisplayEmptyLineAsync, or DisplayIncompatibleVersionErrorAsync) when the backchannel has already completed a successful connection.

Common situations: Calling multiple display/prompt helper methods when the first one already connected, or application code that explicitly calls ConnectAsync after auto-connect already ran during a helper call.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/Backchannel/ExtensionBackchannel.cs:252

        }

        return;

        async Task ConnectCoreAsync()
        {
            if (_connectCoreAsyncOverride is not null)
            {
                await _connectCoreAsyncOverride(cancellationToken).ConfigureAwait(false);
                return;
            }

            try
            {
                using var activity = _activitySource.StartActivity();

                if (_rpcTaskCompletionSource.Task.IsCompleted)
                {
                    throw new InvalidOperationException($"Already connected to {Name} backchannel.");
                }

                _logger.LogDebug("Connecting to {Name} backchannel at {SocketPath}", Name, endpoint);
                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                var addressParts = endpoint.Split(':');
                if (addressParts.Length != 2 || !int.TryParse(addressParts[1], out var port) || port <= 0 ||
                    port > 65535)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ErrorStrings.InvalidSocketPath, endpoint));
                }

                await socket.ConnectAsync(addressParts[0], port, cancellationToken);
                _logger.LogDebug("Connected to {Name} backchannel at {SocketPath}", Name, endpoint);

                var stream = new SslStream(new NetworkStream(socket, true),
                    leaveInnerStreamOpen: true,
                    userCertificateValidationCallback: (_, c, _, e) =>
                    {

View on GitHub (pinned to 25830f84bd)