{"record":{"id":"9c9bcc9e7d0d1e75","repo":"microsoft/aspire","slug":"a-configureradiusinfrastructure-callback-replaced-the","errorCode":null,"errorMessage":"A ConfigureRadiusInfrastructure callback replaced the protocol of port '{portName}' on container '{mapKey}' with a non-literal Bicep expression. Aspire service discovery assumes the literal protocol '{expected.Protocol}', so a computed protocol is not supported. Remove the protocol change.","messagePattern":"A ConfigureRadiusInfrastructure callback replaced the protocol of port '(.+?)' on container '(.+?)' with a non-literal Bicep expression\\. Aspire service discovery assumes the literal protocol '(.+?)', so a computed protocol is not supported\\. Remove the protocol change\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs","lineNumber":4994,"sourceCode":"                // Reject a non-literal port/protocol: service discovery is a fixed literal, so a\n                // callback that swaps in a Bicep expression could evaluate to a different value at\n                // deploy time, reintroducing exactly the mismatch this guard prevents. An\n                // expression-backed BicepValue<int> reports a default LiteralValue of 0 (not null),\n                // so a non-null Expression is the reliable \"non-literal\" signal, not the LiteralValue.\n                var portValueBicep = (IBicepValue)port.ContainerPort;\n                if (portValueBicep.Expression is not null || portValueBicep.LiteralValue is not int literalPort)\n                {\n                    throw new InvalidOperationException(\n                        $\"A ConfigureRadiusInfrastructure callback replaced port '{portName}' on container \" +\n                        $\"'{mapKey}' with a non-literal Bicep expression. Aspire service discovery already emitted \" +\n                        $\"the literal port {expected.Port} into consumer 'services__*' variables and cannot follow a \" +\n                        $\"computed port, so a computed containerPort is not supported. Remove the port change.\");\n                }\n\n                var protocolValueBicep = (IBicepValue)port.Protocol;\n                if (protocolValueBicep.Expression is not null || protocolValueBicep.LiteralValue is not string literalProtocol)\n                {\n                    throw new InvalidOperationException(\n                        $\"A ConfigureRadiusInfrastructure callback replaced the protocol of port '{portName}' on \" +\n                        $\"container '{mapKey}' with a non-literal Bicep expression. Aspire service discovery assumes \" +\n                        $\"the literal protocol '{expected.Protocol}', so a computed protocol is not supported. Remove \" +\n                        $\"the protocol change.\");\n                }\n\n                if (literalPort != expected.Port || !string.Equals(literalProtocol, expected.Protocol, StringComparison.Ordinal))\n                {\n                    throw new InvalidOperationException(\n                        $\"A ConfigureRadiusInfrastructure callback changed port '{portName}' on container \" +\n                        $\"'{mapKey}' from {expected.Port}/{expected.Protocol} to {literalPort}/{literalProtocol}. \" +\n                        $\"Aspire service discovery already emitted {expected.Port}/{expected.Protocol} into consumer \" +\n                        $\"'services__*' variables, so this would break cross-container calls. Remove the port change.\");\n                }\n            }\n        }\n\n        // Validate the FINAL container set. A callback can add the first port to a previously","sourceCodeStart":4976,"sourceCodeEnd":5012,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs#L4976-L5012","documentation":"RadiusInfrastructureBuilder validates that ConfigureRadiusInfrastructure callbacks did not replace a container port's protocol with a computed Bicep expression. Service discovery assumes the literal protocol (e.g. 'tcp' or 'udp') recorded on the Aspire resource; a deploy-time-computed protocol cannot be reconciled with the already-generated 'services__*' connection strings. The builder throws to block an unreproducible manifest.","triggerScenarios":"A ConfigureRadiusInfrastructure callback assigns port.Protocol a BicepValue<string> backed by an Expression, or a value whose LiteralValue is not a string. Triggered when protocolValueBicep.Expression is not null or LiteralValue is not a string.","commonSituations":"Developers try to derive the protocol from a Bicep parameter or module output, or set the protocol with a generic BicepValue helper that produces an expression rather than a literal.","solutions":["Remove the callback line that changes the port protocol, keeping the literal protocol from the Aspire resource","If a different protocol is required, set it on the Aspire endpoint/resource definition itself so service discovery emits the correct value","Use a plain string literal only on the resource definition, never an expression-backed BicepValue in the callback"],"exampleFix":"// before\nport.Protocol = BicepValue<string>.Create(moduleOutputProtocol);\n// after\n// remove the protocol assignment; protocol stays as declared on the endpoint","handlingStrategy":"validation","validationCode":"var v = (IBicepValue)port.Protocol;\nif (v.Expression is not null || v.LiteralValue is not string)\n    throw new InvalidOperationException($\"Port '{portName}' must keep a literal protocol string.\");","typeGuard":"static bool IsLiteralStringProtocol(IBicepValue v) => v.Expression is null && v.LiteralValue is string;","tryCatchPattern":null,"preventionTips":["Use plain string literals (e.g. \"tcp\") for port protocols, never expression-backed BicepValue<string>","Set the protocol on the Aspire endpoint definition so it propagates everywhere consistently","Audit callbacks for any BicepValue.Create calls on protocol properties"],"tags":["radius","publish","bicep","protocol","service-discovery"],"backgroundTag":"unsupported-operation","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"}