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
- Create a separate parameter for the password with builder.AddParameter and pass it to the password API instead of the username parameter
- Give each credential its own name and value, e.g. var userParam = builder.AddParameter("db-user"); var pwdParam = builder.AddParameter("db-pwd");
- 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
- Never reuse one AddParameter result for two different resource properties
- Wrap credential wiring in helpers that always create two distinct parameters
- Search the app model for shared credential variables passed to multiple APIs
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
- A ConfigureRadiusInfrastructure callback changed the value…
- A ConfigureRadiusInfrastructure callback removed or…
- A recipe parameter on Radius environment
- A recipe parameter on Radius environment
- ASPIRERADIUS010
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)