microsoft/aspire · error · InvalidOperationException

A ConfigureRadiusInfrastructure callback changed the value…

Error message

A ConfigureRadiusInfrastructure callback changed the value or encoding of key '{credential.SecretKey}' on the '{RadiusResourceTypes.SecuritySecrets}' resource '{credential.Secret.BicepIdentifier}', which supplies '{credential.PropertyName}' for '{credential.Consumer.BicepIdentifier}'. Consumers were already given the original value.

What it means

Consumers' connection strings were already composed from the original secret value before ConfigureRadiusInfrastructure callbacks run. If a callback changes the value or encoding of the consumed secret key, the provisioned resource would use a credential no consumer knows, so the builder throws ASPIRERADIUS089. The check compares both the reference identity and the rendered value/encoding against the originals.

Solutions

  1. Do not mutate the consumed secret key's value or encoding in the callback.
  2. Supply your own credential via a parameter instead of editing the generated secret.
  3. Point the consuming '{PropertyName}' at a separate secret you create in the callback.
  4. If you need a different credential, change it at the Aspire parameter level before the model is composed, not in the callback.

Example fix

// before
callback: b =>
{
    b.GetSecret("admin-password-secret").Data["password"] = newSecretValue; // diverges from consumers
}

// after
// pass the desired credential as a parameter at model time:
builder.AddParameter("db-password", secret: true);
// then reference that parameter for the resource's password
Defensive patterns

Strategy: validation

Validate before calling

// In a callback, snapshot the consumed entry before mutating and refuse changes
var before = RenderBicepValue(entry.Value) + ":" + RenderBicepValue(entry.Encoding);
// ... mutation attempt ...
if (RenderBicepValue(entry.Value) + ":" + RenderBicepValue(entry.Encoding) != before)
    throw new InvalidOperationException("Cannot change consumed credential secret value/encoding; supply it as a parameter instead.");

Try / catch

try { await builder.ExecuteCallbacksAsync(ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("changed the value or encoding"))
{
    logger.LogError(ex, "Callback mutated a consumed credential; pass the credential as a parameter instead.");
}

Prevention

When it happens

Trigger: A ConfigureRadiusInfrastructure callback assigns a new value (including byte-identical content with a different encoding, which still produces a different Kubernetes Secret) to the secret entry consumed by credential.Consumer's '{PropertyName}'.

Common situations: Callbacks replacing a generated password with an environment-specific one after consumers were already built; changing base64/plain encoding of the entry; reusing the same entry object across callbacks and mutating it in place.

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


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

Appendix: source

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

                throw new InvalidOperationException(
                    $"Radius resource '{credential.Consumer.BicepIdentifier}' reads its '{credential.PropertyName}' from " +
                    $"key '{credential.SecretKey}' of the '{RadiusResourceTypes.SecuritySecrets}' resource " +
                    $"'{credential.Secret.BicepIdentifier}', but a ConfigureRadiusInfrastructure callback removed that " +
                    $"key. The recipe cannot provision the resource without it. Keep the key, or point " +
                    $"'{credential.PropertyName}' at a secret of your own. Diagnostic: ASPIRERADIUS089.");
            }

            // Both an entry swapped for a new construct and one mutated in place are rejected: the
            // credential Aspire projected to consumers is fixed at this point either way. The
            // encoding is checked alongside the value because it decides how the recipe interprets
            // that value — flipping `string` to `base64` makes the recipe decode before writing the
            // Kubernetes Secret, so the provisioned credential diverges from the one consumers hold
            // even though the value is byte-identical.
            if (!ReferenceEquals(liveEntry?.Value, credential.Entry) ||
                !string.Equals(RenderBicepValue(credential.Entry.Value), credential.OriginalEntryValue, StringComparison.Ordinal) ||
                !string.Equals(RenderBicepValue(credential.Entry.Encoding), credential.OriginalEntryEncoding, StringComparison.Ordinal))
            {
                throw new InvalidOperationException(
                    $"A ConfigureRadiusInfrastructure callback changed the value or encoding of key '{credential.SecretKey}' " +
                    $"on the '{RadiusResourceTypes.SecuritySecrets}' resource '{credential.Secret.BicepIdentifier}', which supplies " +
                    $"'{credential.PropertyName}' for '{credential.Consumer.BicepIdentifier}'. Consumers were already given " +
                    $"the original credential in their connection strings, so the deployed resource would require a " +
                    $"credential no consumer has. Supply the credential as a parameter instead, or point " +
                    $"'{credential.PropertyName}' at a secret of your own. Diagnostic: ASPIRERADIUS089.");
            }

            if (string.Equals(credential.Secret.BicepIdentifier, credential.OriginalSecretIdentifier, StringComparison.Ordinal))
            {
                continue;
            }

            credential.Consumer.SetSchemaProperty(
                credential.PropertyName,
                new BicepValue<object>(BuildIdExpression(credential.Secret)));
        }
    }

View on GitHub (pinned to 25830f84bd)