{"record":{"id":"3a1ec469496063c2","repo":"microsoft/aspire","slug":"aspireradius093","errorCode":"ASPIRERADIUS093","errorMessage":"The '${RadiusResourceTypes.SecuritySecrets}' resource '${secret.BicepIdentifier}' has no '${nameof(RadiusSecuritySecretConstruct.EnvironmentId)}'. The type requires 'properties.environment', so Radius would reject the deployment. Assign the environment scope, or remove the resource. Diagnostic: ASPIRERADIUS093.","messagePattern":"The '(.+?)' resource '(.+?)' has no '(.+?)'\\. The type requires 'properties\\.environment', so Radius would reject the deployment\\. Assign the environment scope, or remove the resource\\. Diagnostic: ASPIRERADIUS093\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs","lineNumber":1578,"sourceCode":"    /// producing a compile error. The result is a resource block that is syntactically fine and is\n    /// rejected only by Radius schema validation at <c>rad deploy</c> time, with a message that\n    /// points at the generated artifact rather than at the callback that produced it.\n    /// </para>\n    /// <para>\n    /// The encoding vocabulary is the one place the new type diverges from the legacy\n    /// <c>Applications.Core/secretStores</c> type it replaces: <c>Radius.Security/secrets</c>\n    /// accepts <c>string</c> and <c>base64</c>, where the legacy type accepted <c>raw</c> and\n    /// <c>base64</c>. Radius rejects every value outside its own enum, but only <c>raw</c> is\n    /// rejected here: it is the legacy vocabulary rather than a value a newer control plane might\n    /// introduce, so it is the one spelling that can be called wrong without risking a false\n    /// positive on a gate the AppHost author cannot opt out of.\n    /// </para>\n    /// </remarks>\n    private static void ValidateSecuritySecretRequiredFields(RadiusSecuritySecretConstruct secret)\n    {\n        if (RenderBicepValue(secret.EnvironmentId) is null && !IsBicepExpression(secret.EnvironmentId))\n        {\n            throw new InvalidOperationException(\n                $\"The '{RadiusResourceTypes.SecuritySecrets}' resource '{secret.BicepIdentifier}' has no \" +\n                $\"'{nameof(RadiusSecuritySecretConstruct.EnvironmentId)}'. The type requires \" +\n                $\"'properties.environment', so Radius would reject the deployment. Assign the environment scope, \" +\n                $\"or remove the resource. Diagnostic: ASPIRERADIUS093.\");\n        }\n\n        foreach (var (key, entry) in secret.Data)\n        {\n            // A callback can leave a hole by assigning null, or by adding a key it never populated.\n            // Either way the entry carries no value, which is the same defect the Value check below\n            // catches — reported here because there is no construct left to inspect. An entry whose\n            // whole wrapper is an expression is a different case: it resolves at deploy time and is\n            // skipped rather than rejected, the same way an expression-valued property is.\n            if (entry is null || (entry.Value is null && !IsBicepExpression(entry)))\n            {\n                throw new InvalidOperationException(\n                    $\"The '{RadiusResourceTypes.SecuritySecrets}' resource '{secret.BicepIdentifier}' has a data \" +\n                    $\"entry '{key}' with no value. The type requires a value for every entry, so Radius would \" +","sourceCodeStart":1560,"sourceCodeEnd":1596,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs#L1560-L1596","documentation":"During Radius publish, the builder validates that every Applications.Datastores/enhancedSecret (SecuritySecrets) construct has an environment scope because the Radius type requires 'properties.environment'; without it the deployment would be rejected by Radius. The throw happens in ValidateSecuritySecretRequiredFields when EnvironmentId renders to nothing and is not even a deploy-time Bicep expression.","triggerScenarios":"Adding a RadiusSecuritySecretConstruct to the publish model without assigning its EnvironmentId (the construct was created and added with data entries but the environment scope property was never set, and it is not a Bicep expression).","commonSituations":"Hand-constructing security secret resources in a custom publish callback and forgetting the environment ID; copying a secret construct from a sample that used a different environment variable; refactoring that moved environment assignment behind a condition that never fires.","solutions":["Set the EnvironmentId on the RadiusSecuritySecretConstruct to the target Radius environment (e.g. the environment resource ID produced by the builder).","If the environment is only known at deploy time, assign a Bicep expression instead of a literal so validation skips it.","Remove the secret resource if it is not actually needed."],"exampleFix":"// before\nvar secret = new RadiusSecuritySecretConstruct(\"appSecrets\") { /* EnvironmentId not set */ };\n// after\nvar secret = new RadiusSecuritySecretConstruct(\"appSecrets\") { EnvironmentId = environmentId };","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(secret.EnvironmentId) && !IsBicepExpression(secret.EnvironmentId)) throw new InvalidOperationException($\"Secret '{secret.BicepIdentifier}' is missing EnvironmentId.\");","typeGuard":"bool HasEnvironmentId(RadiusSecuritySecretConstruct s) => !string.IsNullOrWhiteSpace(s.EnvironmentId) || IsBicepExpression(s.EnvironmentId);","tryCatchPattern":null,"preventionTips":["Always set EnvironmentId immediately when constructing a RadiusSecuritySecretConstruct.","Use object initializer syntax so required scope properties are visible at the call site.","Run aspire publish locally before CI to catch validation diagnostics early."],"tags":["radius","publish","bicep","validation"],"backgroundTag":"missing-required-argument","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"}