TL;DR

Start with helm status and helm history. For failed upgrades, check hook Jobs, rendered manifests, and Kubernetes events. Roll back to the last known-good revision before deep-diving into template bugs.

First Steps

Start here when a Helm install or upgrade fails. These commands show release status, revision history, effective values, rendered manifests, and recent Kubernetes events before you decide whether to retry or roll back.

bash first-steps.sh
helm list -A
helm status <release> -n <namespace>
helm history <release> -n <namespace>
helm get values <release> -n <namespace> --all
helm get manifest <release> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -n 30

Symptom → Fix

SymptomLikely causeFix
pending-upgradeHook Job failed or timed outCheck hook Job logs; delete failed Job; retry or rollback
pending-installResources not becoming ready within timeoutkubectl describe failing Pods; increase --timeout
UPGRADE FAILEDInvalid manifest or admission rejectionhelm template --debug; kubectl apply --dry-run=server
Release exists but Pods missingWrong namespace or values disabled resourcehelm get manifest; check enabled: false flags
Manual edit revertedHelm owns the resourceExpected — change values/chart, not kubectl edit
ArgoCD OutOfSync loopHelm and ArgoCD both managing releasePick one owner; disable the other tool's management
Template render errorMissing required value or bad YAML indenthelm template --debug; check nindent usage
another operation in progressConcurrent helm operations on same releaseWait or check for stuck CI job; avoid parallel deploys

Stuck pending-upgrade

Use this when Helm reports a release stuck in pending-upgrade. The usual causes are hook Jobs, timeouts, or concurrent operations, so inspect hooks and Jobs before deleting anything.

bash pending-upgrade.sh
helm status web-api -n app    # STATUS: pending-upgrade
helm get hooks web-api -n app

# Find and inspect hook Jobs.
kubectl get jobs -n app
kubectl logs job/web-api-migrate -n app
kubectl describe job/web-api-migrate -n app

# Option A: fix and retry.
kubectl delete job web-api-migrate -n app
helm upgrade web-api ./chart -n app -f values-prod.yaml --wait

# Option B: rollback immediately.
helm rollback web-api -n app --wait --timeout 10m

Template Render Errors

Use this when Helm fails before it reaches the cluster. Render with debug output so you can find missing values, type mismatches, indentation errors, or bad helper output.

bash render-debug.sh
helm template web-api ./chart -f values-prod.yaml --debug 2>&1 | less
helm lint ./chart --strict

# Common errors:
# "required X is required"  → add missing value to values file.
# "yaml: line N"            → fix indentation; use nindent.
# "cannot unmarshal"        → type mismatch in values (string vs int).

Ownership Conflicts

Helm tracks resources via release secrets and labels. When another tool modifies the same object, upgrades fail or create drift.

bash ownership.sh
# Check if Helm owns a resource.
kubectl get deploy web-api -n app -o yaml | grep -E 'meta.helm.sh|app.kubernetes.io/managed-by'

# Compare live vs Helm desired state.
helm get manifest web-api -n app > /tmp/helm-manifest.yaml
kubectl get deploy web-api -n app -o yaml > /tmp/live-deploy.yaml
diff /tmp/helm-manifest.yaml /tmp/live-deploy.yaml

# ArgoCD-managed release — use argocd, not helm upgrade.
argocd app get web-api
argocd app diff web-api

Emergency Rollback

Use rollback when the fastest safe recovery is returning the release to a known-good revision. Confirm the target revision and remember that Helm rollback does not undo external side effects such as database migrations.

bash emergency-rollback.sh
helm history web-api -n app
helm rollback web-api <revision> -n app --wait --timeout 10m
kubectl rollout status deploy/web-api -n app

# If Helm rollback fails, kubectl-native fallback (last resort).
kubectl rollout undo deploy/web-api -n app
kubectl rollout status deploy/web-api -n app

Release Secrets

Helm stores release state in Secrets (or ConfigMaps in older setups) in the release namespace.

bash release-secrets.sh
kubectl get secrets -n app -l owner=helm
kubectl get secrets -n app | grep 'sh.helm.release'

# Never delete release secrets manually unless recovering a corrupted release.
# Deleting them orphans Helm's view of the release.
⚠️
Do not delete release secrets to "fix" a stuck release unless you fully understand the recovery procedure and have client approval. Prefer rollback or hook Job cleanup first.

Gotchas

  • !helm rollback does not undo DB migrations or external side effects from hook Jobs.
  • !--force replaces resources via delete/recreate — causes downtime; use only with approval.
  • !Helm 3 stores max 10 revisions by default — tune with --history-max if you need longer rollback windows.
  • !Subchart upgrades can change resource names — check for orphaned PVCs or Services after major version bumps.