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

  1. Pass --yes (skip confirmation) to the destroy command when running non-interactive: aspire destroy --yes.
  2. 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.
  3. 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

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


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)