microsoft/aspire · error · InvalidOperationException
Cannot perform destructive operation without confirmation…
Error message
Cannot perform destructive operation without confirmation. Use --yes to skip the confirmation prompt in non-interactive mode.
What it means
Destroying the environment uninstalls the Helm release, which is destructive, so HelmDeploymentEngine requires confirmation. In non-interactive mode (no dashboard/console prompt available via IInteractionService) and without SkipConfirmation (--yes), the engine cannot ask the user, so it refuses to proceed rather than deleting resources unattended.
Solutions
- Pass --yes (skip confirmation) to the destroy command when running non-interactive: aspire destroy --yes.
- If the run should be interactive, execute it in a session where the Aspire interaction service is available (attached dashboard/console prompt) so the confirmation can be answered.
- For automation, gate the destroy step in your pipeline so --yes is only passed after your own approval step.
Example fix
// before (CI script) aspire destroy // after aspire destroy --yes
Defensive patterns
Strategy: validation
Validate before calling
// non-interactive run: always pass the confirmation-skip flag // aspire destroy --yes // or check programmatically that the command args include --yes before invoking destroy in CI
Try / catch
try
{
await deploymentEngine.DestroyAsync(context);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Cannot perform destructive operation without confirmation"))
{
// re-run with --yes or surface a prompt to the user
logger.LogError(ex, "Destroy requires --yes in non-interactive mode");
throw;
} Prevention
- In CI/scripts, always include --yes on aspire destroy after your own approval gate.
- Don't rely on interactive prompts in headless environments - detect non-interactive mode up front and add the flag.
- Gate destructive pipeline steps behind manual approval so --yes is never passed unattended.
When it happens
Trigger: helmDestroyStep calls ConfirmDestroyAsync while options.Value.SkipConfirmation is false and interactionService.IsAvailable is false - i.e. an unattended/non-interactive 'aspire destroy' run (CI, scripts) that was not started with --yes.
Common situations: CI/CD destroy pipelines that omit --yes, scripting aspire destroy against a containerized or headless dashboard where no interactive prompt service exists, or forgetting the flag after it worked interactively on a dev machine.
Understand the failure class
Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.
Related errors
- Cannot perform destructive operation without confirmation…
- Live rendering requires interactive output.
- template
- The option must be specified when running in…
- The option must be specified when running in…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/a18f3ee480374823.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Kubernetes/Deployment/HelmDeploymentEngine.cs:681
}
context.Logger.LogInformation(
"Skipping Helm cleanup for Kubernetes environment '{EnvironmentName}' because the cluster no longer exists.",
environment.Name);
return true;
}
private static async Task ConfirmDestroyAsync(PipelineStepContext context, string message)
{
var options = context.Services.GetRequiredService<IOptions<PipelineOptions>>();
if (!options.Value.SkipConfirmation)
{
var interactionService = context.Services.GetRequiredService<IInteractionService>();
if (!interactionService.IsAvailable)
{
throw new InvalidOperationException(
"Cannot perform destructive operation without confirmation. Use --yes to skip the confirmation prompt in non-interactive mode.");
}
var result = await interactionService.PromptNotificationAsync(
"Destroy environment",
message,
new NotificationInteractionOptions
{
Intent = MessageIntent.Confirmation,
ShowSecondaryButton = true,
ShowDismiss = false,
PrimaryButtonText = "Destroy",
SecondaryButtonText = "Cancel"
},
context.CancellationToken).ConfigureAwait(false);
if (result.Canceled || !result.Data)
{View on GitHub (pinned to 25830f84bd)