microsoft/aspire · error · RadiusBackingResourceProjectionException
ASPIRERADIUS094
ASPIRERADIUS094
Error message
Resource '${resource.Name}' is emitted as a Radius type whose credential requires a '${RadiusResourceTypes.SecuritySecrets}' resource, but no Radius environment was emitted to scope it to. Diagnostic: ASPIRERADIUS094. What it means
The resource is emitted as a Radius type whose credential requires a Security.Secrets resource, but no Radius environment construct exists to scope that secret to. Per the code this is an internal invariant: UDT-emitted resources are always parented to the UDT environment, so this asserts the invariant rather than emitting Bicep Radius would reject.
Solutions
- Ensure the Radius environment is emitted before resources requiring secrets (check ConfigureRadiusInfrastructure customizations are not suppressing it)
- If caused by custom infrastructure callbacks, emit the environment construct before secret-bearing resources
- Report the scenario to the Aspire team as a likely internal invariant violation
Defensive patterns
Strategy: try-catch
Validate before calling
// Before publishing, confirm a Radius environment construct exists:
if (envConstruct is null) throw new InvalidOperationException("Radius environment must be emitted before secret-bearing resources"); Type guard
bool HasEnvironment(RadiusEnvironmentConstruct? e) => e is not null;
Try / catch
try { await publisher.BuildAsync(model); }
catch (RadiusBackingResourceProjectionException ex) when (ex.Message.Contains("ASPIRERADIUS094"))
{ /* report internal invariant bug to Aspire */ } Prevention
- Do not suppress or reorder environment emission in ConfigureRadiusInfrastructure callbacks
- Treat this as a bug report scenario — file it with the Aspire team if reached
When it happens
Trigger: Publishing a resource whose Radius type requires a secret credential (RadiusResourceTypes.SecuritySecrets) when envConstruct is null at line 2676 — i.e. no Radius environment was emitted before the secret was emitted.
Common situations: Effectively a publish-pipeline ordering/invariant bug rather than a user mistake; it may surface after custom ConfigureRadiusInfrastructure callbacks or internal refactors that skip environment emission.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 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
- ASPIRERADIUS042
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/f44a7da4e2f7fb6e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs:2676
/// that resource's outputs without creating a cycle in the deployment graph.
/// </para>
/// </remarks>
private async Task ApplySecretResourceCredentialsAsync(
IResource resource,
IResourceWithConnectionString withConnectionString,
RadiusResourceTypeConstruct construct,
RadiusInfrastructureOptions options,
RadiusEnvironmentConstruct? envConstruct,
RadiusApplicationConstruct? appConstruct,
string propertyName,
string secretKey)
{
// The secret's environment scope is required by the type. A resource emitted as a Radius.*
// UDT is always parented to the UDT environment, so this is unreachable in practice —
// assert it rather than emitting a secret Radius would reject for a missing required scope.
if (envConstruct is null)
{
throw new RadiusBackingResourceProjectionException(
resource,
$"Resource '{resource.Name}' is emitted as a Radius type whose credential requires a " +
$"'{RadiusResourceTypes.SecuritySecrets}' resource, but no Radius environment was emitted to scope it to. " +
$"Diagnostic: ASPIRERADIUS094.");
}
BicepValue<object>? secretValue = null;
var credentialParameter = TryGetCredentialParameter(withConnectionString, propertyName);
if (credentialParameter is not null)
{
RegisterRecipeCredential(credentialParameter, resource, isProjectionSubstitution: false);
secretValue = GetOrAddEnvParameter(credentialParameter);
}
else if (await TryResolveConnectionPropertyAsync(withConnectionString, propertyName).ConfigureAwait(false) is { } resolved)
{
// Not a bare parameter (a composed expression, or a literal). The resolved value is
// still built from `@secure()` param references, so no credential lands in the artifactView on GitHub (pinned to 25830f84bd)