microsoft/aspire · error · InvalidOperationException

A ConfigureRadiusInfrastructure callback replaced container

Error message

A ConfigureRadiusInfrastructure callback replaced container '{container.ContainerMapKey}' name with a non-literal Bicep expression. The Aspire Radius publisher derives service discovery from the original container name, so it must stay the literal resource name '{container.ContainerMapKey}' (this is an Aspire limitation, not a Radius schema requirement). Remove the rename to keep the emitted 'services__*' values addressing the deployed Service.

What it means

This error is thrown by the Aspire Radius publisher when a ConfigureRadiusInfrastructure callback replaces a container's Bicep name with a non-literal Bicep expression (an expression-backed BicepValue instead of a plain string). The publisher derives the emitted 'services__*' service-discovery environment values from the original literal container name, so the name must remain the literal resource name. Aspire throws at publish time to prevent generating broken cross-container discovery values.

Solutions

  1. Remove the rename of container.ContainerName in the ConfigureRadiusInfrastructure callback so it stays the literal resource name
  2. If a computed name is needed, rename the Aspire resource itself (before publishing) rather than mutating the Bicep name in the callback
  3. Use a literal string BicepValue equal to container.ContainerMapKey if you must reassign it

Example fix

// before
callback(ctx => { ctx.Container.ContainerName = BicepValue.Create($"{ctx.Container.ContainerName}-suffix"); });
// after
callback(ctx => { /* keep ContainerName as the literal resource name */ });
Defensive patterns

Strategy: validation

Validate before calling

if (((IBicepValue)container.ContainerName).Expression is not null || ((IBicepValue)container.ContainerName).LiteralValue is not string)
    throw new InvalidOperationException("Container name must remain a literal string in ConfigureRadiusInfrastructure.");

Type guard

static bool IsLiteralStringName(IBicepValue name) => name.Expression is null && name.LiteralValue is string;

Prevention

When it happens

Trigger: Calling WithRadiusInfrastructure/ConfigureRadiusInfrastructure and inside the callback assigning container.ContainerName = new BicepValue<string>(someExpression) or any BicepValue whose Expression is non-null, or whose LiteralValue is not a string (e.g. null literal).

Common situations: Developers try to compute the deployed container name dynamically in Bicep (e.g. from parameters, environment variables, or name suffixes) inside a Radius infrastructure customization callback; this breaks Aspire's discovery generation which needs the static literal.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs:5192

    // Ensures a container's top-level `name:` still equals its `properties.containers` map key. The
    // default name is a literal (the resource name); a callback that changes it to a mismatched
    // literal, or replaces it with a non-literal Bicep expression we cannot compare, throws.
    //
    // NOTE: this is an *Aspire* service-discovery limitation, not a Radius v2 schema requirement.
    // Radius itself permits a container resource whose map keys (e.g. `frontend`, `sidecar`) differ
    // from the top-level name; Aspire derives `services__*` values from the original resource name,
    // so a rename would make the emitted address diverge from the deployed Service.
    private static void ValidateContainerNameMatchesMapKey(RadiusContainerConstruct container)
    {
        var name = (IBicepValue)container.ContainerName;

        // An expression-backed BicepValue reports a default LiteralValue (null for string), but to
        // stay consistent with the port guard we treat any non-null Expression as the non-literal
        // signal.
        if (name.Expression is not null || name.LiteralValue is not string literalName)
        {
            throw new InvalidOperationException(
                $"A ConfigureRadiusInfrastructure callback replaced container '{container.ContainerMapKey}' name " +
                $"with a non-literal Bicep expression. The Aspire Radius publisher derives service discovery from " +
                $"the original container name, so it must stay the literal resource name '{container.ContainerMapKey}' " +
                $"(this is an Aspire limitation, not a Radius schema requirement). Remove the rename to keep the " +
                $"emitted 'services__*' values addressing the deployed Service.");
        }

        if (!string.Equals(literalName, container.ContainerMapKey, StringComparison.Ordinal))
        {
            throw new InvalidOperationException(
                $"A ConfigureRadiusInfrastructure callback renamed container '{container.ContainerMapKey}' to " +
                $"'{literalName}'. The Aspire Radius publisher derives service discovery from the original container " +
                $"name, so renaming it makes the emitted 'services__*' values point at a Service that is no longer " +
                $"produced (this is an Aspire limitation, not a Radius schema requirement). Remove the rename to keep " +
                $"cross-container calls working.");
        }
    }

View on GitHub (pinned to 25830f84bd)