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

  1. Stop removing that secret resource in the ConfigureRadiusInfrastructure callback.
  2. Keep the resource but repoint the consuming property's '{PropertyName}' at a secret you create yourself in the callback.
  3. 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

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


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)