{"record":{"id":"d645b2f5deb5b97a","repo":"microsoft/aspire","slug":"http-s-and-tcp-endpoints-cannot-be-mixed","errorCode":null,"errorMessage":"HTTP(s) and TCP endpoints cannot be mixed","messagePattern":"HTTP\\(s\\) and TCP endpoints cannot be mixed","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.AppContainers/ContainerAppContext.cs","lineNumber":188,"sourceCode":"        // Multiple external endpoints are not supported\n        if (endpointsByTargetPort.Count(g => g.External) > 1)\n        {\n            throw new NotSupportedException(\"Multiple external endpoints are not supported\");\n        }\n\n        // Any external non-http endpoints are not supported\n        if (endpointsByTargetPort.Any(g => g.External && !g.IsHttpOnly))\n        {\n            throw new NotSupportedException(\"External non-HTTP(s) endpoints are not supported\");\n        }\n\n        // Don't allow mixing http and tcp transports on the same target port\n        static bool Compatible(string[] transports) =>\n            transports.All(t => t is \"http\" or \"http2\") || transports.All(t => t is \"tcp\");\n\n        if (endpointsByTargetPort.Any(g => !Compatible(g.UniqueTransports)))\n        {\n            throw new NotSupportedException(\"HTTP(s) and TCP endpoints cannot be mixed\");\n        }\n\n        // Get all http only groups\n        var httpOnlyEndpoints = endpointsByTargetPort.Where(g => g.IsHttpOnly).OrderBy(g => g.Index).ToArray();\n\n        // Do we only have one?\n        var httpIngress = httpOnlyEndpoints.Length == 1 ? httpOnlyEndpoints[0] : null;\n\n        if (httpIngress is null)\n        {\n            // We have more than one, pick prefer external one\n            var externalHttp = httpOnlyEndpoints.Where(g => g.External).ToArray();\n\n            if (externalHttp.Length == 1)\n            {\n                httpIngress = externalHttp[0];\n            }\n            else if (httpOnlyEndpoints.Length > 0)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.AppContainers/ContainerAppContext.cs#L170-L206","documentation":"Within a single Container App ingress (one target port), all endpoints must be either http/http2 or tcp — they cannot be mixed, since the transport determines the ingress configuration. Aspire groups endpoints by target port and throws this NotSupportedException when a group's transports are incompatible.","triggerScenarios":"Two endpoints sharing the same target port where one is tcp and the other is http/http2, e.g., .WithEndpoint(8080, ..., transport: \"tcp\") together with .WithHttpEndpoint(port: 8080) on the same resource.","commonSituations":"Adding an HTTP health-check endpoint on the same port as a raw TCP listener; schema-only endpoints (e.g., scheme 'redis' vs 'http') accidentally differing in transport on one port.","solutions":["Move one of the endpoints to a different target port so each port has a single transport family.","Unify transports on that port (make both tcp, or both http/http2).","Remove the redundant endpoint if it duplicates the same listener."],"exampleFix":"// before\n.WithHttpEndpoint(port: 8080, name: \"http\")\n.WithEndpoint(targetPort: 8080, name: \"raw\").WithTransport(\"tcp\");\n\n// after\n.WithHttpEndpoint(port: 8080, name: \"http\")\n.WithEndpoint(targetPort: 8081, name: \"raw\").WithTransport(\"tcp\");","handlingStrategy":"validation","validationCode":"var byPort = resource.Annotations.OfType<EndpointAnnotation>()\n    .GroupBy(a => a.TargetPort ?? a.Port ?? 0)\n    .Select(g => (Port: g.Key, Transports: g.Select(a => a.Transport ?? \"http\").Distinct().ToList()));\nif (byPort.Any(g => g.Transports is { Count: > 1 } t && t.Contains(\"tcp\") && t.Any(x => x is \"http\" or \"http2\")))\n    throw new InvalidOperationException(\"Cannot mix http and tcp transports on the same target port.\");","typeGuard":"static bool TransportsCompatible(IEnumerable<string> ts) => ts.All(t => t is \"http\" or \"http2\") || ts.All(t => t is \"tcp\");","tryCatchPattern":"try { /* build/publish */ } catch (NotSupportedException ex) when (ex.Message == \"HTTP(s) and TCP endpoints cannot be mixed\") { /* move one endpoint to another port or unify transports */ }","preventionTips":["Assign each transport family its own target port.","Keep health/metrics endpoints on separate ports from raw TCP listeners.","Validate endpoint groupings locally with aspire publish before deploying."],"tags":["azure","container-apps","endpoints","ports"],"backgroundTag":"invalid-argument-value","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"}