microsoft/aspire · error · InvalidOperationException

ASPIRERADIUS070

ASPIRERADIUS070

Error message

Parameter '${userNameParameter.Name}' is used as both the user name and the password of '${resource.Name}'. Its Radius recipe generates a separate value for each, and a single parameter cannot be substituted for both, so consumers would receive the same value for both. Give the user name and the password their own parameters. Diagnostic: ASPIRERADIUS070.

What it means

Thrown when the same parameter instance is supplied as both the user name and the password of a Radius-backed resource. Recipe substitutions are keyed by parameter identity, so one parameter cannot stand in for two different recipe-generated values; assigning both would silently keep only the later substitution and publish the username value where consumers asked for the password.

Solutions

  1. Create a separate parameter for the password with builder.AddParameter and pass it to the password API instead of the username parameter
  2. Give each credential its own name and value, e.g. var userParam = builder.AddParameter("db-user"); var pwdParam = builder.AddParameter("db-pwd");
  3. If the values are genuinely identical, still use two distinct parameters so each substitution key is unique

Example fix

// before
var cred = builder.AddParameter("db-cred", secret: true);
var db = builder.AddPostgres("pg").WithUserName(cred).WithPassword(cred);
// after
var user = builder.AddParameter("db-user");
var pwd = builder.AddParameter("db-pwd", secret: true);
var db = builder.AddPostgres("pg").WithUserName(user).WithPassword(pwd);
Defensive patterns

Strategy: validation

Validate before calling

var user = builder.AddParameter("db-user");
var pwd = builder.AddParameter("db-pwd", secret: true);
if (ReferenceEquals(user.Resource, pwd.Resource))
    throw new InvalidOperationException("username and password must be distinct parameters");

Type guard

bool AreDistinctParameters(object a, object b) => !ReferenceEquals(a, b);

Prevention

When it happens

Trigger: Publishing a Radius resource where WithConnectionString/credential APIs (or ConfigureRadiusInfrastructure) received the identical IResourceBuilder parameter object for both userNameParameter and passwordParameter (checked via ReferenceEquals) in RadiusInfrastructureBuilder around line 2425.

Common situations: Reusing one builder.AddParameter result for both username and password arguments, e.g. builder.AddPostgres(...).WithUserName(param).WithPassword(param), or a helper method that caches a single parameter and passes it to both.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        // Applications.Datastores/mongoDatabases and Applications.Messaging/rabbitMQQueues types
        // return only connectionString and password from listSecrets(), and expose the user the
        // recipe created at properties.username.
        //
        // Known gap: this only works when the AppHost supplied a user-name *parameter*. The default
        // user names ("admin" for MongoDB, "guest" for RabbitMQ) are appended through
        // ReferenceExpressionBuilder.AppendFormatted(string?, string?), which formats immediately
        // and writes the result into the format string, so they arrive here as opaque literal text
        // with no value provider to substitute. Those connection strings keep the default user name.
        if (schema.UserNameProperty is { } userNameProperty &&
            TryGetCredentialParameter(withConnectionString, "username") is { } userNameParameter)
        {
            // Substitutions are keyed by parameter identity — that is all a value provider exposes
            // when an env var is resolved — so one parameter cannot stand for two different
            // recipe-generated values. Assigning both would silently keep only the later one and
            // hand consumers `properties.username` where they asked for the password.
            if (passwordParameter is not null && ReferenceEquals(passwordParameter, userNameParameter))
            {
                throw new InvalidOperationException(
                    $"Parameter '{userNameParameter.Name}' is used as both the user name and the password of " +
                    $"'{resource.Name}'. Its Radius recipe generates a separate value for each, and a single parameter " +
                    $"cannot be substituted for both, so consumers would receive the same value for both. Give the user " +
                    $"name and the password their own parameters. Diagnostic: ASPIRERADIUS070.");
            }

            WarnIfUserSuppliedCredentialIsReplaced(resource, userNameParameter, "user name");
            RegisterRecipeCredential(userNameParameter, resource, isProjectionSubstitution: true);
            _recipeSecretSubstitutions[userNameParameter] =
                new ProjectedValue(construct, userNameProperty, IsSecret: false, IsNumeric: false);
        }
    }

    /// <summary>
    /// Wires a type whose <c>username</c>/<c>password</c> are required schema properties on the
    /// resource: Aspire writes its own parameters there, so the deployed credentials are the ones
    /// already composed into the connection string.
    /// </summary>

View on GitHub (pinned to 25830f84bd)