microsoft/aspire · error · InvalidOperationException

helm uninstall for chart

Error message

helm uninstall for chart '{chart.Name}' failed with exit code {exitCode}

What it means

UninstallHelmChartAsync runs 'helm uninstall' for the chart and throws InvalidOperationException when the helm process exits non-zero. The message includes helm's stderr when captured, otherwise just the exit code. This happens before the deployment state section is cleaned up.

Solutions

  1. Read the helm stderr in the message for the exact cause
  2. If the release was already removed, the state can be cleaned up manually — verify with 'helm list -n <namespace>'
  3. Check cluster connectivity and kubeconfig context
  4. Resolve stuck resources (finalizers) that prevent deletion
Defensive patterns

Strategy: try-catch

Validate before calling

// check the release exists before uninstalling
var ls = await RunHelmAsync("list -n " + @namespace + " -q");
bool exists = ls.Split('\n', StringSplitOptions.RemoveEmptyEntries).Contains(releaseName);

Try / catch

try { await UninstallHelmChartAsync(chart, ...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("helm uninstall"))
{ logger.LogError(ex, "Helm uninstall failed: {Detail}", ex.Message); }

Prevention

When it happens

Trigger: helm uninstall returns non-zero: release not found under the expected name, cluster unreachable, RBAC denial, or helm timing out waiting for resource deletion.

Common situations: Release already uninstalled out-of-band (helm reports 'release: not found'); wrong kubeconfig context; stuck terminating resources blocking uninstall; namespace already deleted.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/9dfa605afedad4d3. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Kubernetes/KubernetesHelmChartExtensions.cs:456

        var exitCode = await helmRunner.RunAsync(
            arguments.ToString(),
            onOutputData: output => logger.LogDebug("helm (stdout): {Output}", output),
            onErrorData: error =>
            {
                stderrBuilder.AppendLine(error);
                logger.LogDebug("helm (stderr): {Error}", error);
            },
            cancellationToken: context.CancellationToken).ConfigureAwait(false);

        if (exitCode != 0)
        {
            var errorOutput = stderrBuilder.ToString().Trim();
            var message = string.IsNullOrEmpty(errorOutput)
                ? $"helm uninstall for chart '{chart.Name}' failed with exit code {exitCode}"
                : $"helm uninstall for chart '{chart.Name}' failed: {errorOutput}";

            throw new InvalidOperationException(message);
        }

        await deploymentStateManager.DeleteSectionAsync(stateSection, context.CancellationToken).ConfigureAwait(false);

        logger.LogInformation(
            "Helm release '{ReleaseName}' uninstalled from namespace '{Namespace}'.",
            releaseName, @namespace);
    }

    private static (string ReleaseName, string Namespace) ResolveReleaseAndNamespace(KubernetesHelmChartResource chart)
    {
        var releaseName = chart.ReleaseName ?? chart.Name;
        var @namespace = chart.Namespace ?? chart.Name;

        // The fallback to chart.Name can produce a value that isn't a valid Helm release name or
        // Kubernetes namespace (uppercase, too long, etc.) — Aspire resource names allow more than
        // DNS labels do. Validate here so the caller gets a clear ArgumentException pointing at
        // WithReleaseName / WithNamespace instead of an opaque helm CLI failure.

View on GitHub (pinned to 25830f84bd)