Helm "lookup" Returns Empty During template/Dry-Run in CI
Helm’s lookup function queries the live cluster, but it returns an empty value during helm template and helm install --dry-run (no cluster connection in render-only mode). Templates that assume lookup always returns data break in CI rendering.
What this error means
A chart that reads an existing Secret/ConfigMap with lookup renders empty fields (or a nil-pointer error) under helm template/--dry-run, even though the object exists, because lookup is not executed against the cluster in those modes.
Error: template: chart/templates/secret.yaml:8:14: executing "..." at <.data.password>:
nil pointer evaluating interface {}.password
# lookup "v1" "Secret" ... returned an empty dict during helm templateDiagnose it: render the chart before you install it
Most Helm failures are visible in the rendered manifests. Template them locally with the same values CI uses and you will usually see the problem without touching the cluster.
# what will actually be applied
helm template <release> <chart> -f values.ci.yaml | head -60
# validate against the live cluster schema without installing
helm install <release> <chart> -f values.ci.yaml --dry-run --debug
# what state is the release actually in?
helm history <release>
helm status <release>Common causes
lookup is a no-op in render-only modes
helm template and helm install --dry-run (client) do not talk to the cluster, so lookup returns an empty map/dict. Code that dereferences the result without guarding then fails.
No default for the missing value
Even during a real install, the looked-up object may not exist yet (first install). Without a fallback, the template errors or renders an empty value.
How to fix it
Guard lookup with a default and existence check
Treat an empty lookup as "not found" and fall back, so render-only modes and first installs both work.
{{- $existing := (lookup "v1" "Secret" .Release.Namespace "api-secret") | default dict }}
password: {{ (get (default dict $existing.data) "password") | default (randAlphaNum 24 | b64enc) }}Use server-side dry-run when you need real lookups
- Run
helm templateonly for static rendering - expectlookupto be empty there. - Use
helm install --dry-run=serverto exercise lookups against the cluster. - Never rely on
lookupfor values that must exist at first install; provide defaults.
How to prevent it
- Always
| default dictalookupresult and guard before dereferencing. - Reserve
lookupfor genuinely cluster-dependent values, with fallbacks. - Use
--dry-run=serverwhen CI validation needs real cluster state.