Skip to main content
DevOps Insightsguides & answers

Helm · troubleshooting

nil pointer evaluating interface {} in a Helm template

The template reads a nested value such as .Values.database.host, and the parent, database, is not set. Give the parent a default, guard it with with, or make it required.

Reproduced on Helm 3.18.2, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • The template and line from the error, and the values files and --set flags used.

Run this first

step 1 of 1
helm template RELEASE . -f VALUES.yaml -s templates/FILE.yaml

Look for The <…> part of the error: the exact path that is nil

Renders the one template with the same values as the failing deploy, without a cluster.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Which message do you see?

Cause space

2 of 2 still possible

  • The parent key is missing, misspelled or nullCommon
  • Inside range or with, the dot is not the chart any moreCommon

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Check it with a tool

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    helm template RELEASE . -f VALUES.yaml -s templates/FILE.yaml

    Renders the one template with the same values as the failing deploy, without a cluster.

    Look for The <…> part of the error: the exact path that is nil

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The parent key is missing, misspelled or null

Common

values.yaml has no database block, a values file spells it differently, or an override sets it to null.

Confirm

helm get values RELEASE --all
helm show values .

Whether the parent key exists, with exactly the spelling the template uses

Fix

  • Default the parent: {{ (.Values.database | default dict).host | default "localhost" }}.
  • Or skip the lines when it is missing: wrap them in {{- with .Values.database }} … {{- end }} and write .host inside.
  • Or fail with a clear message: {{ required "database.host is required" (.Values.database).host }}.
  • Or dig with the values as a map: {{ dig "database" "host" "localhost" .Values.AsMap }}; plain .Values fails.
  • Add the key to values.yaml with a sensible default, so the chart documents it.
host: {{ (.Values.database | default dict).host | default "localhost" | quote }}

Reproduced on Helm 3.18.2: rendered localhost without the key, and the set value with --set database.host=db.

Inside range or with, the dot is not the chart any more

Common

range and with set the dot to the current item, so .Values and .Release are not found.

Confirm

helm template RELEASE . -s templates/FILE.yaml

can't evaluate field Values (or Release) in type interface {}

Fix

  • Use $ for the top level: $.Values.image.tag, $.Release.Name.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Helm can show an empty result for a missing value, but it cannot look inside something that is not there. .Values.database.host asks for host inside database; if database itself is missing, misspelled or set to null, Helm stops. The fix is to handle the missing parent explicitly.

Words used on this page

Scope (.)
What the dot refers to. At the top it is the whole chart context; inside range or with it becomes the current item.
$
Always the top-level context, so $.Values works inside range and with.
What is actually happening

Reproduced on 23 October 2026 with Helm 3.18.2. With database missing from values, {{ .Values.database.host }} stopped helm template with executing at <.Values.database.host>: nil pointer evaluating interface {}.host, exit 1. The same happened when the key was misspelled databse in values.yaml and when --set database=null removed it. helm lint reported the same error.

Inside range, .Values.image.tag failed differently: can't evaluate field Values in type interface {}. The dot was the current list item, not the chart; $.Values.image.tag worked.

Four guards rendered correctly: (.Values.database | default dict).host | default "localhost"; a with .Values.database block; required with (.Values.database).host, which printed its own message; and dig "database" "host" "localhost" .Values.AsMap. dig with plain .Values failed with interface {} is chartutil.Values, not map[string]interface {}.

How to tell this is your problem
WhereWhat you see
helm template, install, upgrade or lintexecuting "CHART/templates/FILE.yaml" at <.Values.database.host>: nil pointer evaluating interface {}.host
Inside range or withat <.Values.image.tag>: can't evaluate field Values in type interface {}

How to know it is actually fixed

  • helm template renders with and without the value set, and helm lint passes.

Stopping it happening again

  • Give every nested block a default in values.yaml, even an empty one (database: {}).
  • Render the chart in CI with each values file you deploy with.
  • Add a values.schema.json: with database required, helm template stopped with database is required instead of a nil pointer.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it