{"record":{"id":"36cc8dd54ca01990","repo":"microsoft/aspire","slug":"azure-environment-resource-required-by-aks-environment-name","errorCode":null,"errorMessage":"Azure environment resource required by AKS environment '{Name}' was not found.","messagePattern":"Azure environment resource required by AKS environment '(.+?)' was not found\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs","lineNumber":106,"sourceCode":"            return Task.FromResult<IEnumerable<PipelineStep>>([prepareStep, getCredentialsStep, getDestroyCredentialsStep]);\n        }));\n\n        Annotations.Add(new PipelineConfigurationAnnotation(async context =>\n        {\n            var k8sEnv = KubernetesEnvironment;\n            var getDestroyCredentialsStep = context.GetSteps(this)\n                .Single(step => step.Name == $\"aks-get-credentials-for-destroy-{Name}\");\n            var kubernetesDestroySteps = context\n                .GetSteps(HelmDeploymentEngine.GetKubernetesDestroyTag(k8sEnv.Name))\n                .ToList();\n\n            var deploymentStateManager = context.Services.GetRequiredService<IDeploymentStateManager>();\n            var deploymentStateSection = await deploymentStateManager\n                .AcquireSectionAsync($\"Azure:Deployments:{Name}\")\n                .ConfigureAwait(false);\n\n            var azureEnvironment = context.Model.Resources.OfType<AzureEnvironmentResource>().SingleOrDefault()\n                ?? throw new InvalidOperationException(\n                    $\"Azure environment resource required by AKS environment '{Name}' was not found.\");\n            var destroyAzureStep = context.GetSteps(azureEnvironment)\n                .SingleOrDefault(step => step.Name == $\"destroy-azure-{azureEnvironment.Name}\")\n                ?? throw new InvalidOperationException(\n                    $\"Azure destroy step for environment '{azureEnvironment.Name}' was not found.\");\n\n            // A never-deployed AKS environment has no isolated kubeconfig to acquire. Likewise, a\n            // partially deployed environment can persist the cluster ID before any Helm release saves\n            // destroy state. In either case, aggregate Azure cleanup must skip cluster-scoped destroy\n            // steps rather than block on reacquiring credentials when there is nothing known to clean\n            // up. Explicitly targeting one of those Kubernetes cleanup steps still runs through the\n            // credential prerequisite and fails rather than allowing the command to fall back to the\n            // caller's ambient Kubernetes context.\n            var targetStep = context.Services.GetRequiredService<IOptions<PipelineOptions>>().Value.Step;\n            var hasPersistedAksIdentity = HasPersistedAksIdentity(deploymentStateSection.Data);\n            var hasPersistedKubernetesCleanupState = hasPersistedAksIdentity &&\n                await HasPersistedKubernetesCleanupStateAsync(\n                    deploymentStateManager,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs#L88-L124","documentation":"When the AKS environment runs its destroy-related steps, it depends on the single AzureEnvironmentResource in the application model, which owns the Azure provisioning/deployment state. If no such resource exists in the model, Aspire cannot find the Azure deployment scope or the destroy pipeline, so it throws. Every AKS environment is expected to be paired with exactly one Azure environment resource.","triggerScenarios":"Executing the AKS environment's build/destroy steps when the application model contains zero (or the SingleOrDefault path cannot yield exactly one) AzureEnvironmentResource - e.g. the Azure environment was removed from the AppHost, added conditionally behind a flag, or the AKS resource was constructed in an app model without its Azure counterpart.","commonSituations":"Refactoring the AppHost to use an existing-resource-only setup and dropping AddAzureEnvironment; a `if (builder.ExecutionContext.IsPublishMode)` guard that skips adding the Azure environment; copying an AKS environment into a different AppHost that lacks the Azure pairing.","solutions":["Add the Azure environment resource to the AppHost (e.g. builder.AddAzureEnvironment(...)) alongside the AKS environment.","Remove the conditional guard that omits AddAzureEnvironment in the execution mode being run.","Ensure exactly one AzureEnvironmentResource is registered - duplicates would also break the SingleOrDefault contract.","Compare against a working AppHost sample to confirm the required resource pairing."],"exampleFix":"// before\nvar aks = builder.AddAzureKubernetesEnvironment(\"aks\");\n// (no AddAzureEnvironment anywhere)\n\n// after\nbuilder.AddAzureEnvironment(\"azure\");\nvar aks = builder.AddAzureKubernetesEnvironment(\"aks\");","handlingStrategy":"type-guard","validationCode":"var azureEnv = appModel.Resources.OfType<AzureEnvironmentResource>().SingleOrDefault();\nif (azureEnv is null)\n    throw new InvalidOperationException(\"AppHost must call AddAzureEnvironment before using an AKS environment.\");","typeGuard":"bool HasAzureEnvironment(Aspire.Hosting.ApplicationModel.IResource model) =>\n    model.Resources.OfType<AzureEnvironmentResource>().Any();","tryCatchPattern":null,"preventionTips":["Always pair AddAzureKubernetesEnvironment with AddAzureEnvironment in the AppHost","Do not conditionally skip AddAzureEnvironment behind publish-mode flags without also handling AKS","Review AppHost refactors for dropped resources"],"tags":["azure","aks","app-model","missing-resource"],"backgroundTag":"resource-not-found","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"}