{"record":{"id":"f44a7da4e2f7fb6e","repo":"microsoft/aspire","slug":"aspireradius094","errorCode":"ASPIRERADIUS094","errorMessage":"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.","messagePattern":"Resource '(.+?)' is emitted as a Radius type whose credential requires a '(.+?)' resource, but no Radius environment was emitted to scope it to\\. Diagnostic: ASPIRERADIUS094\\.","errorType":"validation","errorClass":"RadiusBackingResourceProjectionException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs","lineNumber":2676,"sourceCode":"    /// that resource's outputs without creating a cycle in the deployment graph.\n    /// </para>\n    /// </remarks>\n    private async Task ApplySecretResourceCredentialsAsync(\n        IResource resource,\n        IResourceWithConnectionString withConnectionString,\n        RadiusResourceTypeConstruct construct,\n        RadiusInfrastructureOptions options,\n        RadiusEnvironmentConstruct? envConstruct,\n        RadiusApplicationConstruct? appConstruct,\n        string propertyName,\n        string secretKey)\n    {\n        // The secret's environment scope is required by the type. A resource emitted as a Radius.*\n        // UDT is always parented to the UDT environment, so this is unreachable in practice —\n        // assert it rather than emitting a secret Radius would reject for a missing required scope.\n        if (envConstruct is null)\n        {\n            throw new RadiusBackingResourceProjectionException(\n                resource,\n                $\"Resource '{resource.Name}' is emitted as a Radius type whose credential requires a \" +\n                $\"'{RadiusResourceTypes.SecuritySecrets}' resource, but no Radius environment was emitted to scope it to. \" +\n                $\"Diagnostic: ASPIRERADIUS094.\");\n        }\n\n        BicepValue<object>? secretValue = null;\n\n        var credentialParameter = TryGetCredentialParameter(withConnectionString, propertyName);\n        if (credentialParameter is not null)\n        {\n            RegisterRecipeCredential(credentialParameter, resource, isProjectionSubstitution: false);\n            secretValue = GetOrAddEnvParameter(credentialParameter);\n        }\n        else if (await TryResolveConnectionPropertyAsync(withConnectionString, propertyName).ConfigureAwait(false) is { } resolved)\n        {\n            // Not a bare parameter (a composed expression, or a literal). The resolved value is\n            // still built from `@secure()` param references, so no credential lands in the artifact","sourceCodeStart":2658,"sourceCodeEnd":2694,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs#L2658-L2694","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before publishing, confirm a Radius environment construct exists:\nif (envConstruct is null) throw new InvalidOperationException(\"Radius environment must be emitted before secret-bearing resources\");","typeGuard":"bool HasEnvironment(RadiusEnvironmentConstruct? e) => e is not null;","tryCatchPattern":"try { await publisher.BuildAsync(model); }\ncatch (RadiusBackingResourceProjectionException ex) when (ex.Message.Contains(\"ASPIRERADIUS094\"))\n{ /* report internal invariant bug to Aspire */ }","preventionTips":["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"],"tags":["radius","publishing","internal-invariant","secrets"],"backgroundTag":"internal-invariant-violation","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}