Common Helm Issues
A comprehensive guide to common Helm issues covering troubleshooting, causes, solutions, and best practices for resolving frequent Helm problems.
Helm is a powerful tool, but like any complex system, it can encounter issues. Most problems fall into several categories: template errors, value issues, dependency problems, release management issues, and cluster connectivity issues.
This guide covers the most frequently encountered Helm issues and provides step-by-step solutions. Always start by checking the Helm debug output (helm install --dry-run --debug) to identify the specific error message.
- Run
helm lintto check chart syntax - Run
helm template --debugto see rendered output - Run
helm install --dry-run --debugfor full simulation - Check pod logs and events for runtime issues
- Review release history and status
Template Errors
YAML Parse Errors
Upgrade Failures
Timeout Issues
Dependency Issues
Permission Issues
Cause: Accessing a value that doesn't exist in the values file.
# Bad: Fails if database is nil
{{ .Values.database.host }}
# Good: Use default
{{ .Values.database.host | default "localhost" }}
# Good: Use with block
{{- with .Values.database }}
host: {{ .host }}
port: {{ .port }}
{{- end }}
# Good: Use required for mandatory values
{{ required "Database host is required" .Values.database.host }}
Cause: Missing helper template or typo in function name.
# Check _helpers.tpl for the template
{{- define "my-app.labels" -}}
app: {{ include "my-app.name" . }}
{{- end }}
# Use include (not template) for pipeline support
{{ include "my-app.labels" . }}
# Check template names
helm template my-release ./my-chart --debug | grep "my-app"
Cause: Trying to loop over a non-list value.
# Bad: Fails if env is not a list
{{- range .Values.env }}
- name: {{ .name }}
{{- end }}
# Good: Use default empty list
{{- range .Values.env | default (list) }}
- name: {{ .name }}
{{- end }}
# Good: Use with to check
{{- with .Values.env }}
{{- range . }}
- name: {{ .name }}
{{- end }}
{{- end }}
- Use
defaultfor fallback values - Use
withto check if values exist - Use
requiredfor mandatory values - Use
listfor empty list defaults - Use
--show-onlyto isolate templates - Use
--debugto see rendered output
Cause: Incorrect indentation or missing values.
# Bad: Indentation issues
metadata:
name: {{ .Values.name }}
labels:
{{ toYaml .Values.labels }}
# Good: Use nindent
metadata:
name: {{ .Values.name }}
labels:
{{- toYaml .Values.labels | nindent 4 }}
# Bad: Missing quotes
value: {{ .Values.password }} # Fails with special chars
# Good: Use quote
value: {{ .Values.password | quote }}
# Bad: Incorrect toYaml
resources:
{{ toYaml .Values.resources }}
# Good: Use nindent with correct indentation
resources:
{{- toYaml .Values.resources | nindent 2 }}
Cause: Type mismatch between values and expected types.
# Bad: String where integer expected
replicas: {{ .Values.replicaCount }} # Fails if string
# Good: Convert to integer
replicas: {{ .Values.replicaCount | int }}
# Bad: Integer where string expected
value: {{ .Values.port }} # Fails in some contexts
# Good: Convert to string
value: {{ .Values.port | quote }}
- Always use
nindentwithtoYaml - Use
quotefor string values - Use
intfor integer values - Validate with
kubeconformorkubectl apply --dry-run - Use
--debugto inspect rendered YAML
Cause: Immutable field changed in Deployment.
# Common immutable fields:
# - spec.selector
# - spec.template.metadata.labels
# - spec.volumeClaimTemplates (StatefulSet)
# Fix 1: Use --force to recreate resources
helm upgrade my-release ./my-chart --force
# Fix 2: Delete and reinstall
kubectl delete deployment my-app --ignore-not-found
helm upgrade my-release ./my-chart
# Fix 3: Use --atomic for automatic rollback
helm upgrade my-release ./my-chart --atomic
Cause: Resource already exists outside of Helm.
# Check if resource exists
kubectl get deployment my-app
# Fix 1: Delete existing resource
kubectl delete deployment my-app --ignore-not-found
helm upgrade my-release ./my-chart
# Fix 2: Use --force
helm upgrade my-release ./my-chart --force
# Fix 3: Adopt existing resources
kubectl label deployment my-app app.kubernetes.io/managed-by=Helm
kubectl annotate deployment my-app meta.helm.sh/release-name=my-release
kubectl annotate deployment my-app meta.helm.sh/release-namespace=default
helm upgrade my-release ./my-chart
Cause: Another Helm operation is in progress or failed.
# Check release status
helm status my-release
# Check release history
helm history my-release
# Fix 1: Wait for operation to complete
# Check if any pending operations
# Fix 2: Force unlock (if operation stuck)
kubectl delete secret -n default sh.helm.release.v1.my-release.v1
# Fix 3: Rollback to previous revision
helm rollback my-release 1
# Fix 4: Use --force
helm upgrade my-release ./my-chart --force
- Use
--forceto recreate immutable resources - Use
--atomicfor automatic rollback on failure - Delete conflicting resources manually
- Check release history and status
- Use
--dry-runto preview changes - Test upgrades in staging first
Cause: Resources not ready within the timeout period.
# Check pod status
kubectl get pods -n default
kubectl describe pod my-app-pod
kubectl logs my-app-pod
# Fix 1: Increase timeout
helm install my-release ./my-chart --timeout 15m
helm upgrade my-release ./my-chart --timeout 15m
# Fix 2: Check resource limits
kubectl describe pod my-app-pod | grep -A 5 "Limits"
# Fix 3: Check image pull issues
kubectl describe pod my-app-pod | grep -A 5 "Events"
# Fix 4: Check readiness probes
kubectl get pod my-app-pod -o yaml | grep -A 10 "readinessProbe"
# Fix 5: Disable wait for debugging
helm install my-release ./my-chart --wait=false
# Fix 6: Check for resource quotas
kubectl get resourcequotas --all-namespaces
kubectl describe resourcequota -n default
Cause: Operation took longer than the configured timeout.
# Check if resources are being created
kubectl get all -n default
# Check for pending pods
kubectl get pods --field-selector status.phase=Pending
# Fix 1: Increase timeout
helm install my-release ./my-chart --timeout 30m
# Fix 2: Check cluster capacity
kubectl top nodes
kubectl describe nodes | grep -A 5 "Allocated resources"
# Fix 3: Check for image pull issues
kubectl describe pod my-app-pod | grep -A 10 "Events"
# Fix 4: Check for PVC binding issues
kubectl get pvc -n default
kubectl describe pvc my-app-pvc
- Check pod events with
kubectl describe pod - Check resource quotas and limits
- Verify image pull secrets
- Check PVC binding status
- Monitor cluster resource usage
- Increase timeout for large deployments
Cause: Dependencies not downloaded.
# Check dependencies
helm dependency list ./my-chart
# Fix 1: Update dependencies
helm dependency update ./my-chart
# Fix 2: Build dependencies
helm dependency build ./my-chart
# Fix 3: Check for dependency conflicts
helm dependency list ./my-chart --outdated
# Fix 4: Verify repository access
helm repo list
helm repo update
Cause: Repository URL invalid or network issue.
# Check repository
helm repo list
# Fix 1: Update repository
helm repo update
# Fix 2: Remove and re-add repository
helm repo remove bitnami
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Fix 3: Check network connectivity
curl -I https://charts.bitnami.com/bitnami/index.yaml
# Fix 4: Check DNS resolution
nslookup charts.bitnami.com
# Fix 5: Use OCI registry instead
helm pull oci://registry-1.docker.io/bitnami/nginx --version 15.0.0
Cause: Corrupted repository cache.
# Fix 1: Clear repository cache
rm -rf ~/.cache/helm/repository/*
helm repo update
# Fix 2: Re-add repositories
helm repo remove $(helm repo list -o json | jq -r '.[].name')
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Fix 3: Check Helm home directory permissions
ls -la ~/.cache/helm/
chmod -R 755 ~/.cache/helm/
- Run
helm dependency updatebefore install - Run
helm dependency buildfrom Chart.lock - Clear cache if corrupted
- Verify repository URLs and network
- Use OCI registries for dependencies
- Pin dependency versions
Cause: Insufficient RBAC permissions.
# Check permissions
kubectl auth can-i create deployments --as=system:serviceaccount:default:my-sa
kubectl auth can-i create secrets --as=system:serviceaccount:default:my-sa
# Fix 1: Create appropriate RBAC
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-role
namespace: default
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
# Fix 2: Bind role to service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: helm-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: my-sa
namespace: default
roleRef:
kind: Role
name: helm-role
apiGroup: rbac.authorization.k8s.io
# Fix 3: Use cluster-admin for testing (not production)
kubectl create clusterrolebinding helm-admin \
--clusterrole=cluster-admin \
--serviceaccount=default:my-sa
Cause: Namespace doesn't exist and isn't created.
# Fix 1: Create namespace manually
kubectl create namespace my-namespace
helm install my-release ./my-chart --namespace my-namespace
# Fix 2: Use --create-namespace
helm install my-release ./my-chart \
--namespace my-namespace \
--create-namespace
# Fix 3: Add CreateNamespace=true to syncPolicy (ArgoCD)
syncPolicy:
syncOptions:
- CreateNamespace=true
- Use least privilege for Helm service accounts
- Create namespaces before installation
- Use
--create-namespacewhen needed - Regularly audit RBAC permissions
- Use namespaced roles instead of cluster roles
Cause: Release name conflict.
# Check existing releases
helm list
helm list --all-namespaces
# Fix 1: Uninstall existing release
helm uninstall my-release
helm install my-release ./my-chart
# Fix 2: Use different release name
helm install my-release-2 ./my-chart
# Fix 3: Upgrade existing release
helm upgrade my-release ./my-chart
# Fix 4: Use --generate-name
helm install ./my-chart --generate-name
Cause: Release in failed or pending state.
# Check release status
helm status my-release
helm history my-release
# Fix 1: Uninstall with keep history
helm uninstall my-release --keep-history
# Fix 2: Force delete release secrets
kubectl delete secret sh.helm.release.v1.my-release.v1 -n default
# Fix 3: Rollback to previous revision
helm rollback my-release 1
# Fix 4: Use --force
helm upgrade my-release ./my-chart --force
- Use consistent release naming
- Check
helm list --allbefore installing - Clean up failed releases
- Use
--keep-historyfor auditing - Monitor release status regularly
helm lint to check syntax, then helm template --debug to see rendered output, and finally helm install --dry-run --debug for full simulation.default for fallback values, with to check if values exist, or required for mandatory values. Example: {{ .Values.database.host | default "localhost" }}.toYaml. Use nindent with toYaml, quote for strings, and validate with kubeconform.helm upgrade --force to recreate resources, or delete the resource manually and reinstall. Immutable fields include spec.selector and spec.volumeClaimTemplates.--timeout 15m. Check pod events for underlying issues like image pull failures, resource constraints, or PVC binding problems.helm dependency update to download dependencies. If cache is corrupted, clear it with rm -rf ~/.cache/helm/repository/* and re-add repositories.kubectl auth can-i. Create appropriate Roles and RoleBindings for the service account. Use --create-namespace if namespace is missing.helm uninstall, use a different release name, or use --generate-name. Clean up failed releases.Most Helm issues have straightforward solutions once you understand the root cause. Use systematic debugging, leverage the tools available, and always test in a non-production environment first.