{"record":{"id":"075bf3fe31f0b94f","repo":"microsoft/aspire","slug":"already-connected-to-name-backchannel","errorCode":null,"errorMessage":"Already connected to {Name} backchannel.","messagePattern":"Already connected to (.+?) backchannel\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Backchannel/ExtensionBackchannel.cs","lineNumber":252,"sourceCode":"        }\n\n        return;\n\n        async Task ConnectCoreAsync()\n        {\n            if (_connectCoreAsyncOverride is not null)\n            {\n                await _connectCoreAsyncOverride(cancellationToken).ConfigureAwait(false);\n                return;\n            }\n\n            try\n            {\n                using var activity = _activitySource.StartActivity();\n\n                if (_rpcTaskCompletionSource.Task.IsCompleted)\n                {\n                    throw new InvalidOperationException($\"Already connected to {Name} backchannel.\");\n                }\n\n                _logger.LogDebug(\"Connecting to {Name} backchannel at {SocketPath}\", Name, endpoint);\n                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\n                var addressParts = endpoint.Split(':');\n                if (addressParts.Length != 2 || !int.TryParse(addressParts[1], out var port) || port <= 0 ||\n                    port > 65535)\n                {\n                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ErrorStrings.InvalidSocketPath, endpoint));\n                }\n\n                await socket.ConnectAsync(addressParts[0], port, cancellationToken);\n                _logger.LogDebug(\"Connected to {Name} backchannel at {SocketPath}\", Name, endpoint);\n\n                var stream = new SslStream(new NetworkStream(socket, true),\n                    leaveInnerStreamOpen: true,\n                    userCertificateValidationCallback: (_, c, _, e) =>\n                    {","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Backchannel/ExtensionBackchannel.cs#L234-L270","documentation":"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.","triggerScenarios":"Calling ConnectAsync (directly or indirectly through DisplayMessageAsync, DisplaySuccessAsync, DisplaySubtleMessageAsync, DisplayErrorAsync, DisplayEmptyLineAsync, or DisplayIncompatibleVersionErrorAsync) when the backchannel has already completed a successful connection.","commonSituations":"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.","solutions":["Do not call ConnectAsync if already connected; check the connected state (or wrap in try/catch for InvalidOperationException) before connecting.","Call ConnectAsync once during initialization and rely on subsequent helper methods to reuse the existing connection.","If a reconnection is genuinely needed, dispose/reset the backchannel instance before connecting again."],"exampleFix":"// before\nawait backchannel.ConnectAsync(endpoint, cancellationToken);\nawait backchannel.ConnectAsync(endpoint, cancellationToken); // throws\n\n// after\nif (Volatile.Read(ref backchannel._connected) == 0)\n{\n    await backchannel.ConnectAsync(endpoint, cancellationToken);\n}","handlingStrategy":"type-guard","validationCode":"if (backchannel.IsConnected) return; // skip redundant ConnectAsync","typeGuard":"bool shouldConnect = !backchannel.IsConnected;","tryCatchPattern":"try { await backchannel.ConnectAsync(endpoint, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Already connected\"))\n{ /* ignore: connection already established */ }","preventionTips":["Call ConnectAsync exactly once during initialization.","Guard helper-method usage with a connected check before forcing a connect.","Centralize connection establishment in one place instead of per-call connects."],"tags":["backchannel","connection","invalid-state","cli"],"backgroundTag":"invalid-state-transition","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"}