microsoft/aspire · error · InvalidOperationException
ASPIRERADIUS074
ASPIRERADIUS074
Error message
Radius resource '{credential.Consumer.BicepIdentifier}' reads its '{credential.PropertyName}' from the '{RadiusResourceTypes.SecuritySecrets}' resource '{credential.OriginalSecretIdentifier}', but a ConfigureRadiusInfrastructure callback removed it. The property is required, so the deployment would be rejected. Keep the secret, or point '{credential.PropertyName}' at a secret of your own. Diagnostic: ASPIRERADIUS074. What it means
Aspire generates a Security/secrets resource supplying required credential properties for Radius resources, and consumers' Bicep properties are wired to it. A ConfigureRadiusInfrastructure callback removed that secret resource from the model; since the property is required, Radius would reject the deployment, so the builder throws early with ASPIRERADIUS074.
Solutions
- Stop removing that secret resource in the ConfigureRadiusInfrastructure callback.
- Keep the resource but repoint the consuming property's '{PropertyName}' at a secret you create yourself in the callback.
- Only remove generated secrets when you also replace every credential property that referenced them.
Example fix
// before
callback: b =>
{
b.RemoveResource("admin-password-secret"); // breaks consumers
}
// after
callback: b =>
{
// keep the generated secret, or replace it AND repoint the consumer:
// b.SetProperty("cache", "password", myOwnSecretRef);
} Defensive patterns
Strategy: validation
Validate before calling
// Inside ConfigureRadiusInfrastructure, never remove generated secret resources
callback: b =>
{
foreach (var name in resourcesToRemove)
{
if (b.GetResource(name) is { IsGeneratedCredentialSecret: true })
throw new InvalidOperationException($"Refusing to remove credential secret '{name}' — it is consumed by a required property.");
}
} Try / catch
try { await builder.ExecuteCallbacksAsync(ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ASPIRERADIUS074"))
{
logger.LogError(ex, "A callback removed a required credential secret; restore it or repoint the property.");
} Prevention
- Never delete generated Security/secrets resources in ConfigureRadiusInfrastructure callbacks
- Filter callback removals by explicit allow-list, not by resource type
- If replacing a secret, repoint every consumer property to your own secret in the same callback
When it happens
Trigger: Inside a ConfigureRadiusInfrastructure callback, removing (or filtering out) the generated SecuritySecrets resource that a credential-bearing property of another Radius resource still references (tracked via credential.OriginalSecretIdentifier).
Common situations: Callback code that deletes all generated helper resources to 'clean up' the Bicep; a builder loop that removes secrets it does not recognize; overzealous resource filtering that breaks credential references.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Radius resource ' ' reads its ' ' from key ' ' of the ' '…
- A ConfigureRadiusInfrastructure callback changed the value…
- ASPIRERADIUS047
- ASPIRERADIUS048
- ASPIRERADIUS051
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/b7e36d8196b7388c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs:946
continue;
}
// The callback took ownership of the property, so this relationship is no longer the
// publisher's to enforce — last-write-wins, exactly as for container env values and
// projected type properties. This has to be decided *before* the checks below: those
// reject removing the secret or changing the credential, which are legitimate once the
// consumer no longer reads from it. The credential schema properties are internal, so
// the typed surface offers no way to reassign one, but the `ProvisionableProperties`
// dictionary inherited from Azure.Provisioning is public and reaches the same values.
if (credential.Consumer.GetSchemaProperty(credential.PropertyName) is not { } currentProperty ||
!string.Equals(RenderBicepValue(currentProperty), credential.OriginalPropertyValue, StringComparison.Ordinal))
{
continue;
}
if (!liveSecrets.Contains(credential.Secret))
{
throw new InvalidOperationException(
$"Radius resource '{credential.Consumer.BicepIdentifier}' reads its '{credential.PropertyName}' from " +
$"the '{RadiusResourceTypes.SecuritySecrets}' resource '{credential.OriginalSecretIdentifier}', but a " +
$"ConfigureRadiusInfrastructure callback removed it. The property is required, so the deployment would " +
$"be rejected. Keep the secret, or point '{credential.PropertyName}' at a secret of your own. " +
$"Diagnostic: ASPIRERADIUS074.");
}
// The consumer still reads this secret, so the entry carrying the credential has to
// survive intact. Unlike a container env secret — whose only reader is the variable that
// points at it, so a callback replacing the value is self-consistent — this value is
// handed to the *recipe* that provisions the server, while the matching credential was
// already composed into every consumer's connection string from Aspire's own parameter.
// Removing it prevents the recipe from starting; changing it provisions a server with a
// password no consumer was told about, which fails only as an authentication error at
// runtime. Neither can be repaired here, so both are rejected.
if (!credential.Secret.Data.TryGetValue(credential.SecretKey, out var liveEntry))
{
throw new InvalidOperationException(View on GitHub (pinned to 25830f84bd)