microsoft/aspire · error · InvalidOperationException
A ConfigureRadiusInfrastructure callback changed port
Error message
A ConfigureRadiusInfrastructure callback changed port '{portName}' on container '{mapKey}' from {expected.Port}/{expected.Protocol} to {literalPort}/{literalProtocol}. Aspire service discovery already emitted {expected.Port}/{expected.Protocol} into consumer 'services__*' variables, so this would break cross-container calls. Remove the port change. What it means
RadiusInfrastructureBuilder compares each port's literal containerPort/protocol after a ConfigureRadiusInfrastructure callback against the expected values Aspire recorded when service discovery emitted 'services__*' variables for consumers. If the callback changed either value, the deployed Kubernetes Service would no longer match the endpoints consumers already received, silently breaking cross-container calls. The builder throws to stop publication of the inconsistent manifest.
Solutions
- Revert the port/protocol change in the callback so the values match what Aspire emitted (expected.Port / expected.Protocol)
- Change the port or protocol on the Aspire resource/endpoint definition instead, so both the container and all consumers are updated consistently
- Delete the ConfigureRadiusInfrastructure callback if it exists only to adjust ports
Example fix
// before container.Ports["http"].ContainerPort = 8080; // expected 8000 // after // no port change in callback; declare the desired port on the Aspire endpoint instead
Defensive patterns
Strategy: validation
Validate before calling
if (literalPort != expected.Port || !string.Equals(literalProtocol, expected.Protocol, StringComparison.Ordinal))
throw new InvalidOperationException($"Port '{portName}' must stay {expected.Port}/{expected.Protocol}."); Prevention
- Treat ConfigureRadiusInfrastructure callbacks as read-only for ports and protocols
- If a port must change, change it at the Aspire resource level so consumers' services__* values update too
- Any port edit must happen before service discovery values are computed
When it happens
Trigger: A callback assigns a literal int to port.ContainerPort or a literal string to port.Protocol that differs from the expected values (expected.Port / expected.Protocol). The comparison uses ordinal equality on the protocol.
Common situations: Developers remap a container port inside a container (e.g. to 8080) or flip http to tcp in a ConfigureRadiusInfrastructure callback, not realizing the port value was already propagated to consumers' environment variables.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- A ConfigureRadiusInfrastructure callback replaced port
- A ConfigureRadiusInfrastructure callback left container
- A ConfigureRadiusInfrastructure callback replaced the…
- A ConfigureRadiusInfrastructure callback removed or…
- A ConfigureRadiusInfrastructure callback removed port
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/570cd4df3b6a2b28.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs:5003
$"A ConfigureRadiusInfrastructure callback replaced port '{portName}' on container " +
$"'{mapKey}' with a non-literal Bicep expression. Aspire service discovery already emitted " +
$"the literal port {expected.Port} into consumer 'services__*' variables and cannot follow a " +
$"computed port, so a computed containerPort is not supported. Remove the port change.");
}
var protocolValueBicep = (IBicepValue)port.Protocol;
if (protocolValueBicep.Expression is not null || protocolValueBicep.LiteralValue is not string literalProtocol)
{
throw new InvalidOperationException(
$"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.");
}
if (literalPort != expected.Port || !string.Equals(literalProtocol, expected.Protocol, StringComparison.Ordinal))
{
throw new InvalidOperationException(
$"A ConfigureRadiusInfrastructure callback changed port '{portName}' on container " +
$"'{mapKey}' from {expected.Port}/{expected.Protocol} to {literalPort}/{literalProtocol}. " +
$"Aspire service discovery already emitted {expected.Port}/{expected.Protocol} into consumer " +
$"'services__*' variables, so this would break cross-container calls. Remove the port change.");
}
}
}
// Validate the FINAL container set. A callback can add the first port to a previously
// portless container, add a new container, or add a second endpoint. Once a container
// declares ports the recipe creates a Service, so re-check the two things the recipe cares
// about on the post-callback state: the Service name fits the Kubernetes limit, and the
// container's ports are unique by (containerPort, protocol).
foreach (var container in options.Containers)
{
if (container.Ports.Count == 0)
{
continue;View on GitHub (pinned to 25830f84bd)