microsoft/aspire · error
Azure destroy step for environment
Error message
Azure destroy step for environment '{azureEnvironment.Name}' was not found. What it means
Having found the AzureEnvironmentResource, the AKS environment locates its sibling Azure destroy step (named 'destroy-azure-<name>') so cluster-scoped cleanup can be sequenced with/after aggregate Azure cleanup. If that step is not registered on the Azure environment resource, the expected pipeline contract is violated and Aspire throws rather than skipping Azure destroy silently.
Solutions
- Ensure the default Azure environment pipeline is intact so its 'destroy-azure-<name>' step is registered; remove customizations that drop or rename it.
- Verify the step name matches exactly ('destroy-azure-' + azureEnvironment.Name) if creating steps manually.
- Align Azure.Kubernetes and Azure hosting package versions so both agree on step naming conventions.
- Check eventing/interception code that mutates GetSteps output for the Azure environment.
Example fix
// before
// custom step filtering removed the destroy step
steps.RemoveAll(s => s.Name.StartsWith("destroy-azure"));
// after
// keep the destroy step; only reorder around it
var destroy = steps.Single(s => s.Name == $"destroy-azure-{azure.Name}");
// schedule other steps relative to destroy Defensive patterns
Strategy: type-guard
Validate before calling
var destroyStep = context.GetSteps(azureEnvironment)
.SingleOrDefault(s => s.Name == $"destroy-azure-{azureEnvironment.Name}");
if (destroyStep is null)
throw new InvalidOperationException("Azure destroy step missing; ensure the default Azure pipeline is unmodified."); Type guard
bool HasAzureDestroyStep(IResource azureEnv, string stepName) =>
context.GetSteps(azureEnv).Any(s => s.Name == stepName); Prevention
- Do not remove or rename default Azure environment steps in custom pipelines
- Keep Azure.Kubernetes and Azure hosting packages version-aligned
- Test destroy mode after any pipeline customization
When it happens
Trigger: Executing AKS destroy steps when context.GetSteps(azureEnvironment) contains zero or multiple steps named 'destroy-azure-<azureEnvironment.Name>' - e.g. a customized/overridden Azure environment pipeline that removed or renamed the destroy step, or duplicate-step registration breaking SingleOrDefault.
Common situations: Custom pipeline transformations that filter or rename Azure steps; using an older/newer Azure hosting package where step naming changed relative to the AKS package; intercepting events to strip destroy steps in publish-only setups.
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
- No Azure deployment state was found for AKS environment
- The Azure deployment state for AKS environment
- The Azure deployment state for AKS environment
- az aks get-credentials failed
- az resource list failed
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/431d3e950b78d175.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs:110
{
var k8sEnv = KubernetesEnvironment;
var getDestroyCredentialsStep = context.GetSteps(this)
.Single(step => step.Name == $"aks-get-credentials-for-destroy-{Name}");
var kubernetesDestroySteps = context
.GetSteps(HelmDeploymentEngine.GetKubernetesDestroyTag(k8sEnv.Name))
.ToList();
var deploymentStateManager = context.Services.GetRequiredService<IDeploymentStateManager>();
var deploymentStateSection = await deploymentStateManager
.AcquireSectionAsync($"Azure:Deployments:{Name}")
.ConfigureAwait(false);
var azureEnvironment = context.Model.Resources.OfType<AzureEnvironmentResource>().SingleOrDefault()
?? throw new InvalidOperationException(
$"Azure environment resource required by AKS environment '{Name}' was not found.");
var destroyAzureStep = context.GetSteps(azureEnvironment)
.SingleOrDefault(step => step.Name == $"destroy-azure-{azureEnvironment.Name}")
?? throw new InvalidOperationException(
$"Azure destroy step for environment '{azureEnvironment.Name}' was not found.");
// A never-deployed AKS environment has no isolated kubeconfig to acquire. Likewise, a
// partially deployed environment can persist the cluster ID before any Helm release saves
// destroy state. In either case, aggregate Azure cleanup must skip cluster-scoped destroy
// steps rather than block on reacquiring credentials when there is nothing known to clean
// up. Explicitly targeting one of those Kubernetes cleanup steps still runs through the
// credential prerequisite and fails rather than allowing the command to fall back to the
// caller's ambient Kubernetes context.
var targetStep = context.Services.GetRequiredService<IOptions<PipelineOptions>>().Value.Step;
var hasPersistedAksIdentity = HasPersistedAksIdentity(deploymentStateSection.Data);
var hasPersistedKubernetesCleanupState = hasPersistedAksIdentity &&
await HasPersistedKubernetesCleanupStateAsync(
deploymentStateManager,
context.Model,
k8sEnv).ConfigureAwait(false);
if (!hasPersistedAksIdentity || !hasPersistedKubernetesCleanupState)View on GitHub (pinned to 25830f84bd)