I ran an upgrade with --set image.tag=v2.0.0, but the Deployment continued to use the previous image. The tempting explanation was that a later --values argument overrode --set. That explanation is incorrect: Helm gives --set higher specificity than a user-supplied values file.
Verify the value at each stage
Start with the release and namespace you actually upgraded:
helm list --all-namespaces | grep my-app
helm get values my-app -n production --all
helm get manifest my-app -n production | grep -n "image:"Next, render the exact command locally before applying it:
helm template my-app ./chart \
--namespace production \
--values prod-values.yaml \
--set-string image.tag=v2.0.0 \
--debug > /tmp/my-app-rendered.yaml
grep -n "image:" /tmp/my-app-rendered.yamlIf the rendered manifest has the old image, the problem is in values or templating. If the rendered manifest is correct but the live Deployment is wrong, check that the upgrade targeted the expected release, namespace, context, and workload.
Common causes
1. The chart reads a different key
The values file may define image.tag, while the template reads another path:
# values.yaml
image:
repository: ghcr.io/example/my-app
tag: latest# deployment template must read the same path
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"Inspect the chart rather than assuming the key name:
grep -R "Values.*image" ./chart/templates ./chart/charts
helm show values ./chart | grep -A5 '^image:'For a dependency chart, the key may need the subchart name, such as --set api.image.tag=v2.0.0.
2. The value needs to remain a string
Tags such as 1.0, commit-like numeric values, or values with leading zeros can be parsed into an unintended YAML type. Use --set-string when the chart expects a string:
helm upgrade my-app ./chart \
-n production \
-f prod-values.yaml \
--set-string image.tag=1.03. A later flag of the same type wins
When several -f files define the same key, the right-most values file wins. When several --set flags define the same key, the right-most --set value wins:
helm upgrade my-app ./chart \
-f base.yaml \
-f production.yaml \
--set image.tag=v1 \
--set image.tag=v2Here, production.yaml wins over base.yaml, and v2 wins over v1. The --set value remains more specific than values supplied through -f.
4. The release or namespace is wrong
An upgrade can succeed against one namespace while you inspect another:
kubectl config current-context
helm status my-app -n production
kubectl get deployment my-app -n production \
-o jsonpath='{.spec.template.spec.containers[*].image}{"\n"}'The fix I would keep in CI
Render the chart, check the output, and make the namespace explicit:
helm upgrade --install my-app ./chart \
--namespace production \
--create-namespace \
--values prod-values.yaml \
--set-string image.tag="$GIT_SHA" \
--wait \
--timeout 5mFor another image-specific diagnostic, see Helm deployed the wrong image tag. For a broader workflow, see building a GitOps pipeline with Argo CD and Helm.