What's Actually Happening
Helm chart values from values.yaml or custom values files are not being applied during installation or upgrade. Deployed resources use default values instead of custom values, causing configuration drift.
The Error You'll See
Values ignored:
```bash $ helm install my-release my-chart -f custom-values.yaml
# Resources deployed with wrong config: $ kubectl get deployment my-app -o jsonpath='{.spec.replicas}'
1 # Expected 3 from custom-values.yaml ```
Values not overriding defaults:
```bash # In custom-values.yaml: replicaCount: 3
# But deployment still uses: $ helm get values my-release USER-SUPPLIED VALUES: replicaCount: 3 # Shows correct
$ helm get manifest my-release | grep replicas replicas: 1 # But manifest has default ```
Template not using values:
```bash $ helm template my-chart -f custom-values.yaml | grep image:
image: "nginx:latest" # Expected custom image ```
Why This Happens
- 1.Value path mismatch - Value path doesn't match template reference
- 2.YAML syntax error - Invalid YAML causing file to be ignored
- 3.Values not passed - Forgot -f flag or wrong file
- 4.Value precedence issue - Values overridden by other sources
- 5.Template syntax error - Template not using .Values correctly
- 6.Cached values - Previous release values cached
Step 1: Check Helm Release Values
```bash # Get all values for release helm get values my-release --all
# Get user-supplied values only helm get values my-release
# Get values in YAML format helm get values my-release -o yaml
# Get values with computed defaults helm get values my-release --all -o yaml
# Compare to expected values helm get values my-release -o yaml > actual-values.yaml diff custom-values.yaml actual-values.yaml
# Check release history helm history my-release
# Get values from specific revision helm get values my-release --revision 2 ```
Step 2: Verify Values File Syntax
```bash # Validate YAML syntax cat custom-values.yaml | python -m yaml
# Or use yamllint yamllint custom-values.yaml
# Common YAML mistakes: # - Wrong indentation (must be 2 spaces) # - Missing quotes for special characters # - Colon without space after # - Mixing tabs and spaces
# Check indentation cat -A custom-values.yaml | head -20 # Should show spaces (^I = tabs, wrong)
# Validate with helm helm lint my-chart -f custom-values.yaml
# Use --debug to see computed values helm install my-release my-chart -f custom-values.yaml --debug --dry-run ```
Step 3: Check Value Path Structure
```bash # In values.yaml: # parent: # child: # key: value
# In template: # {{ .Values.parent.child.key }}
# Common mistake - wrong path:
# values.yaml: config: database: host: localhost
# WRONG template reference: {{ .Values.database.host }} # Missing config parent
# CORRECT template reference: {{ .Values.config.database.host }}
# Check actual values structure: helm get values my-release --all -o json | jq 'paths'
# Debug in template: debug: {{ .Values | toYaml }} ```
Step 4: Check Values Precedence
```bash # Helm values precedence (lowest to highest): # 1. Chart values.yaml (defaults) # 2. Parent chart values.yaml (if subchart) # 3. User-supplied values file (-f) # 4. Values from --set # 5. Values from --set-file # 6. Values from --set-string # 7. Values from --set-json (highest)
# Check what values are applied: helm get values my-release --all
# Test with debug: helm template my-chart \ -f custom-values.yaml \ --set key1=value1 \ --debug
# If -f values overridden by --set: # --set takes precedence
# Multiple -f files (later overrides earlier): helm install my-release my-chart \ -f values.yaml \ -f custom-values.yaml \ -f production-values.yaml # This wins
# Check specific value: helm get values my-release -o jsonpath='{.replicaCount}' ```
Step 5: Debug Template Rendering
```bash # Render templates without installing helm template my-chart -f custom-values.yaml
# Render specific template helm template my-chart -f custom-values.yaml -s templates/deployment.yaml
# Debug with verbose output helm template my-chart -f custom-values.yaml --debug
# Check computed values helm template my-chart -f custom-values.yaml | grep -A 5 "replicas"
# Use helm pull to inspect chart helm pull my-chart --untar --untardir ./chart-inspect cat ./chart-inspect/my-chart/values.yaml
# Test template rendering helm install my-release my-chart -f custom-values.yaml --dry-run --debug ```
Step 6: Check for Global Values Issues
```yaml # Global values must use .Values.global
# In values.yaml: global: imageRegistry: my-registry.com
# In template: # WRONG: image: {{ .Values.imageRegistry }}/my-app
# CORRECT: image: {{ .Values.global.imageRegistry }}/my-app
# For subcharts, global values are shared: # Parent values.yaml: global: imageRegistry: my-registry.com
# Subchart can access: # {{ .Values.global.imageRegistry }}
# Non-global values are NOT shared to subcharts: # Parent: database: host: db-server # Not visible to subcharts
# Subchart values.yaml: database: host: localhost # Subchart uses its own ```
Step 7: Fix Value Merging Issues
```yaml # Helm merges values deeply, but lists are replaced entirely
# Default values.yaml: config: ports: - 80 - 443
# Custom values.yaml: config: ports: - 8080
# Result: ports = [8080] (list replaced, not merged!)
# To preserve and add: # Use null to remove: config: ports: - null # Remove 80 - null # Remove 443 - 8080 - 8443
# Or specify full list: config: ports: - 80 - 443 - 8080
# For maps, values are merged: # Default: config: database: host: localhost port: 5432
# Custom: config: database: host: prod-db
# Result: # config.database.host = prod-db # config.database.port = 5432 (preserved) ```
Step 8: Check Chart Dependencies
```bash # Check chart dependencies helm dependency list my-chart
# Update dependencies helm dependency update my-chart
# Build dependencies helm dependency build my-chart
# Check subchart values cat my-chart/charts/subchart/values.yaml
# Subchart values can be overridden: # In parent values.yaml: subchart: enabled: true config: key: value
# The subchart name must match ```
Step 9: Force Refresh Values
```bash # Force helm to refresh values:
# Option 1: Uninstall and reinstall helm uninstall my-release helm install my-release my-chart -f custom-values.yaml
# Option 2: Upgrade with reset-values helm upgrade my-release my-chart -f custom-values.yaml --reset-values
# --reset-values clears cached values and uses only provided values
# Option 3: Force resource replacement helm upgrade my-release my-chart -f custom-values.yaml --force
# Check upgrade changes helm upgrade my-release my-chart -f custom-values.yaml --dry-run
# Verify values applied helm get values my-release --all ```
Step 10: Monitor and Validate Deployments
```bash # Create validation script cat << 'EOF' > validate_helm_values.sh #!/bin/bash RELEASE=my-release NAMESPACE=default
echo "=== Release Values ===" helm get values $RELEASE --all -o yaml
echo "" echo "=== Expected vs Actual Replicas ===" EXPECTED=$(helm get values $RELEASE -o jsonpath='{.replicaCount}') ACTUAL=$(kubectl get deployment -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE -o jsonpath='{.items[0].spec.replicas}') echo "Expected: $EXPECTED" echo "Actual: $ACTUAL"
echo "" echo "=== Image Check ===" EXPECTED_IMAGE=$(helm get values $RELEASE -o jsonpath='{.image.repository}'):$(helm get values $RELEASE -o jsonpath='{.image.tag}') ACTUAL_IMAGE=$(kubectl get deployment -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE -o jsonpath='{.items[0].spec.template.spec.containers[0].image}') echo "Expected: $EXPECTED_IMAGE" echo "Actual: $ACTUAL_IMAGE"
echo "" echo "=== Release History ===" helm history $RELEASE EOF
chmod +x validate_helm_values.sh
# Run validation ./validate_helm_values.sh
# Use helm diff plugin helm plugin install https://github.com/databus23/helm-diff helm diff upgrade my-release my-chart -f custom-values.yaml ```
Helm Values Application Checklist
| Check | Command | Expected |
|---|---|---|
| Values syntax | yamllint | Valid YAML |
| Values passed | helm get values | Shows custom values |
| Template refs | grep .Values | Correct path |
| Precedence | helm template | Correct override |
| Merging | helm get values --all | Expected merged values |
| Dry run | helm install --dry-run | Matches expected |
Verify the Fix
```bash # After fixing value application
# 1. Check values are passed helm get values my-release -o yaml // Shows custom values
# 2. Verify manifest has correct values helm get manifest my-release | grep -E "replicas|image:" // Shows expected values
# 3. Check deployed resources kubectl get deployment my-app -o yaml | grep -E "replicas|image:" // Matches custom values
# 4. Compare to values file diff <(helm get values my-release -o yaml) custom-values.yaml // Should match or have expected differences
# 5. Test upgrade applies new values helm upgrade my-release my-chart -f updated-values.yaml --dry-run // Shows changes in diff
# 6. Verify release history helm history my-release // Shows upgrade with new values ```
Related Issues
- [Fix Helm Chart Template Render Failed](/articles/fix-helm-chart-template-render-failed)
- [Fix Helm Release Failed](/articles/fix-helm-release-failed)
- [Fix Helm Chart Dependency Missing](/articles/fix-helm-chart-dependency-missing)