{"record":{"id":"696c35e73f8bca18","repo":"microsoft/aspire","slug":"aspireradius087","errorCode":"ASPIRERADIUS087","errorMessage":"A ConfigureRadiusInfrastructure callback left environment variable '{key}' on container '{container.ContainerMapKey}' with neither a 'value' nor a 'valueFrom.secretKeyRef'. The variable would be dropped from the deployed container. Assign either Value or the SecretName/SecretKey pair. Diagnostic: ASPIRERADIUS087.","messagePattern":"A ConfigureRadiusInfrastructure callback left environment variable '(.+?)' on container '(.+?)' with neither a 'value' nor a 'valueFrom\\.secretKeyRef'\\. The variable would be dropped from the deployed container\\. Assign either Value or the SecretName/SecretKey pair\\. Diagnostic: ASPIRERADIUS087\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs","lineNumber":5097,"sourceCode":"    /// a rejected manifest at <c>rad deploy</c> time.\n    /// </para>\n    /// <para>\n    /// Assignment is detected with <see cref=\"RenderBicepValue\"/> rather than a null check on the\n    /// property: <c>DefineProperty</c> returns a non-null <see cref=\"BicepValue{T}\"/> in an unset\n    /// state, so an unassigned property is only recognisable by having neither an expression nor a\n    /// literal — the same test <c>ProjectedEnvValue.OriginalValue</c> relies on.\n    /// </para>\n    /// </remarks>\n    private static void ValidateContainerEnvVarForms(RadiusInfrastructureOptions options)\n    {\n        foreach (var container in options.Containers)\n        {\n            foreach (var (key, entry) in container.Env)\n            {\n                // BicepDictionary wraps each entry; a callback can leave a hole by assigning null.\n                if (entry?.Value is not { } envVar)\n                {\n                    throw new InvalidOperationException(\n                        $\"A ConfigureRadiusInfrastructure callback left environment variable '{key}' on container \" +\n                        $\"'{container.ContainerMapKey}' with neither a 'value' nor a 'valueFrom.secretKeyRef'. The \" +\n                        $\"variable would be dropped from the deployed container. Assign either Value or the \" +\n                        $\"SecretName/SecretKey pair. Diagnostic: ASPIRERADIUS087.\");\n                }\n\n                var hasValue = RenderBicepValue(envVar.Value) is not null;\n                var hasSecretName = RenderBicepValue(envVar.SecretName) is not null;\n                var hasSecretKey = RenderBicepValue(envVar.SecretKey) is not null;\n\n                // Neither form assigned. Radius accepts the empty object and the Kubernetes recipe\n                // emits no `value` and no `valueFrom`, so the variable the callback added is absent\n                // from the deployed container — the same silent drop the two checks below exist to\n                // prevent, reached by leaving everything unset rather than by setting too much.\n                if (!hasValue && !hasSecretName && !hasSecretKey)\n                {\n                    throw new InvalidOperationException(\n                        $\"A ConfigureRadiusInfrastructure callback left environment variable '{key}' on container \" +","sourceCodeStart":5079,"sourceCodeEnd":5115,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Publishing/RadiusInfrastructureBuilder.cs#L5079-L5115","documentation":"RadiusInfrastructureBuilder validates each environment variable on a Radius container and throws when an entry is null or its Value is unset with no usable value. An env var with neither a literal value nor a secret reference would simply be dropped from the deployed container, so the builder surfaces the problem at publish time instead. This is the guard for entries left as holes (e.g. by assigning null through the BicepDictionary wrapper).","triggerScenarios":"A ConfigureRadiusInfrastructure callback leaves container.Env[key] null, or the BicepDictionary entry has no Value — detected when entry?.Value is not { } envVar. Diagnostic code ASPIRERADIUS087.","commonSituations":"Assigning null to an env var in a callback intending to 'clear' it, or constructing an environment entry but forgetting to set Value before publishing.","solutions":["Assign a Value to the environment variable entry, or set its SecretName/SecretKey pair","If the variable was meant to be removed, delete the entry entirely rather than assigning null","Remove the callback line that created the empty entry"],"exampleFix":"// before\ncontainer.Env[\"FEATURE_FLAG\"] = null;\n// after\ncontainer.Env[\"FEATURE_FLAG\"] = new() { Value = \"true\" };","handlingStrategy":"validation","validationCode":"if (container.Env[key]?.Value is null)\n    throw new InvalidOperationException($\"Env var '{key}' needs a Value or SecretName/SecretKey.\");","typeGuard":"static bool HasUsableEntry(BicepDictionary<RadiusEnvValue>.Entry? e) => e?.Value is not null;","tryCatchPattern":"try { /* publish */ }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"ASPIRERADIUS087\"))\n{\n    // fix the env entry or drop it entirely\n}","preventionTips":["Never assign null to an env var entry to 'clear' it — remove the entry instead","Only add env entries once the value or secret reference is known","Search callbacks for assignments that may be conditional/no-op"],"tags":["radius","publish","env-var","validation","aspireradius087"],"backgroundTag":"missing-required-config-field","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"}