HelmHelm

Error: another operation (install/upgrade/rollback) is in progress

A previous Helm operation was interrupted and the release is stuck pending. How to tell a genuinely running operation from an abandoned one, and clear it safely.

medium fix5 min read

the helm error
Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress

Error: INSTALLATION FAILED: another operation (install/upgrade/rollback) is in progress

STATUS: pending-upgrade

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

  1. 1

    Check whether something really is still running

    helm list -n production --all --filter '^api$' && kubectl get pods -n production -l app.kubernetes.io/instance=api

    A pending status with Pods actively rolling means the operation is genuinely in flight and you should wait. A pending status with nothing happening, and a timestamp from hours ago, means the process that started it is gone.

  2. 2

    See how long it has been stuck

    kubectl get secret -n production -l owner=helm,name=api --sort-by=.metadata.creationTimestamp -o custom-columns=NAME:.metadata.name,STATUS:.metadata.labels.status,AGE:.metadata.creationTimestamp

    The newest Secret carries the pending status and its creation time tells you when the operation started. Anything older than your Helm timeout is abandoned.

  3. 3

    Roll the release back to clear the pending state

    helm rollback api -n production

    From Helm 3.13 this is the supported way to recover a stuck release. It creates a new revision from the last good one and clears the pending status.

All 8 sections

Helm marks a release pending-install, pending-upgrade or pending-rollback while an operation runs, and refuses any concurrent operation. If the process doing the work dies, nothing clears the marker and every subsequent command is refused.

The usual causes are a cancelled CI job, a runner terminated mid-deploy, a laptop closed during an upgrade, or helm upgrade --wait timing out in a way that left the state behind.

Is it actually running?

Do not skip this. Clearing a live operation causes real damage.

helm list -n production --all --filter '^api$'
NAME  REVISION  UPDATED                   STATUS           CHART
api   4         2026-09-21 06:12:09 UTC   pending-upgrade  api-1.4.2

Compare UPDATED against now. A pending state from four hours ago, with a default Helm timeout of five minutes, is abandoned.

Then look at whether anything is moving:

kubectl get pods -n production -l app.kubernetes.io/instance=api
kubectl rollout status deployment/api -n production --timeout=10s

Pods actively being created or terminated means the operation may still be progressing, and waiting is correct. A stable set of Pods with an old timestamp means nothing is happening.

Clear it

From Helm 3.13 the supported route is a rollback:

helm rollback api -n production

That creates a new revision from the last successful one and clears the pending marker. Check it worked:

helm list -n production --all --filter '^api$'
helm history api -n production

When rollback is refused

A release stuck in pending-install has no successful revision to roll back to:

helm history api -n production
REVISION  STATUS            CHART
1         pending-install   api-1.4.2

Uninstall it, since nothing was ever deployed:

helm uninstall api -n production
kubectl get all -n production -l app.kubernetes.io/instance=api    # check for leftovers
helm install api ./chart -n production

The last resort: delete the revision Secret

Only when rollback and uninstall both fail, and only after confirming nothing is running.

Helm stores each revision as a Secret. Deleting the pending one makes the previous revision current again:

kubectl get secret -n production -l owner=helm,name=api \
  --sort-by=.metadata.creationTimestamp \
  -o custom-columns=NAME:.metadata.name,STATUS:.metadata.labels.status
NAME                        STATUS
sh.helm.release.v1.api.v3   superseded
sh.helm.release.v1.api.v4   pending-upgrade
kubectl delete secret sh.helm.release.v1.api.v4 -n production

Helm now sees revision 3 as current. Note that this only changes Helm's bookkeeping: whatever the interrupted upgrade already applied to the cluster stays applied. So Helm's view and reality can differ, and the next helm upgrade reconciles them. Run a diff first if you can:

helm diff upgrade api ./chart -n production      # needs the helm-diff plugin

Preventing it

Use --atomic with a realistic --timeout:

helm upgrade --install api ./chart -n production \
  --atomic --timeout 10m

--atomic rolls back automatically if the upgrade fails or times out, so a failure leaves a clean deployed release rather than a stuck pending one. It implies --wait.

The timeout has to exceed your slowest realistic rollout. The default is five minutes, which a large StatefulSet or a slow image pull can exceed easily, and then --atomic rolls back a deployment that was actually fine.

Make the CI job hard to interrupt mid-operation. Where the platform allows it, mark the deploy step non-cancellable, or set the job timeout above the Helm timeout so the job cannot be killed while Helm is working.

Do not run two deploys at once. Concurrency controls on the pipeline prevent two jobs upgrading the same release:

# GitHub Actions
concurrency:
  group: deploy-production
  cancel-in-progress: false

cancel-in-progress: false matters. Cancelling an in-flight deploy is precisely how releases get stuck.

Helm 3 has no lock

Worth knowing: there is no distributed lock. The pending status in the release Secret is the only guard, and it is advisory. Two helm upgrade commands started at the same instant can both proceed, which produces interleaved changes and a release history that does not describe reality. Pipeline-level concurrency control is the actual protection.

A checklist

  1. helm list -n <ns> --all and read UPDATED. Compare against your timeout.
  2. kubectl get pods -l app.kubernetes.io/instance=<release>. Anything moving?
  3. Genuinely running → wait.
  4. Abandoned → helm rollback <release> -n <ns>.
  5. pending-install with no good revision → helm uninstall then install again.
  6. Last resort → delete the pending revision Secret, after confirming nothing runs.
  7. Prevent with --atomic --timeout 10m and a timeout above your slowest rollout.
  8. Add pipeline concurrency control with cancel-in-progress: false.

Frequently Asked Questions

How do I know whether the operation is really still running?

Compare the UPDATED timestamp from helm list --all against your Helm timeout. A release pending for longer than the timeout cannot still be progressing under Helm's own supervision. Then check the cluster: kubectl get pods -l app.kubernetes.io/instance=<release> and kubectl rollout status. Pods being created or terminated mean something is genuinely happening and you should wait. A stable set of Pods with an hours-old timestamp means the process that started the operation is gone.

Is it safe to delete the Helm release Secret?

Only as a last resort, after confirming no operation is running. Deleting the pending revision Secret changes Helm's bookkeeping and nothing else: whatever the interrupted operation already applied to the cluster stays applied, so Helm's recorded state and the real state can diverge. The next upgrade reconciles them, which is usually fine but can produce a surprising diff. Try helm rollback first, since from Helm 3.13 it handles this case properly.

What does --atomic do and should I always use it?

--atomic makes Helm roll back automatically if the upgrade fails or times out, so a failed deploy leaves a clean deployed release rather than a stuck pending one. It implies --wait, so Helm blocks until resources are ready. It is a good default for pipelines, with one caveat: the --timeout must exceed your slowest realistic rollout, because otherwise a perfectly healthy but slow deployment is rolled back. The five minute default is frequently too short for large StatefulSets or slow image pulls.

Why did my release get stuck after I cancelled the CI job?

Because cancelling kills the Helm process while the release is marked pending, and nothing then clears the marker. Helm has no background reconciler to notice the operation was abandoned. Prevent it with pipeline concurrency control set to queue rather than cancel, cancel-in-progress: false in GitHub Actions, and by making the job timeout longer than the Helm timeout so the runner cannot kill Helm mid-operation.

Does Helm prevent two concurrent upgrades of the same release?

Not reliably. There is no distributed lock; the pending status written into the release Secret is the only guard, and it is advisory rather than enforced. Two helm upgrade commands issued at nearly the same moment can both proceed, interleaving their changes and producing a release history that does not describe what is actually deployed. Real protection has to come from outside Helm, through pipeline concurrency groups or a deployment queue.

Reference and practice

Learn the underlying concept

Other Helm errors