← Back to Helm Values Schema Check

Why Helm silently accepts a typo in values.yaml

The mechanism

A Helm chart template reads values.yaml through Go's text/template/html/template engine as .Values.image.repository, a lookup into a plain nested map. Go's template engine returns the zero value for a map key that was never set -- an empty string, not an error. So if values.yaml actually sets image.repositry (missing an "o"), the template asking for .Values.image.repository gets back nothing, the typo'd key sits there unused, and the chart renders successfully -- usually with a blank, or a hard-coded chart default silently standing in for what the user meant to override.

Nothing about the render signals this went wrong. helm template exits 0. The Pod comes up, possibly pulling the chart's default image instead of the one the values file was supposed to specify, and the mistake surfaces later, if at all -- as a "why is it running the wrong version" investigation days after the values file was written and reviewed.

Why helm lint does not catch it

Helm has supported values.schema.json validation since 3.5.0 -- a real, useful gate, when a chart ships one. But JSON Schema's default for an object is permissive: a field the schema does not mention in properties is allowed unless the schema explicitly sets additionalProperties: false on that object. Most real charts' schemas -- written once, rarely revisited -- do not set it. So image.repositry next to a schema that declares image.repository is, as far as JSON Schema and therefore helm lint are concerned, just an extra field. Not required, not forbidden, not wrong. Lint passes. The typo ships.

Schema saysvalues.yaml sets image.repositry (typo)helm lint result
additionalProperties: falseRejectedFails -- the schema is doing its job
unset (JSON Schema default)Allowed as an extra fieldPasses -- lint has nothing to object to

What this tool looks for, and why it stops where it does

It walks values.yaml against values.schema.json and reports two different things at two different severities. A real schema violation -- a missing required field, a wrong type, a value outside an enum or a minimum/maximum, or a field forbidden by an explicit additionalProperties: false -- is reported as something helm install --dry-run --validate would already reject. A field the schema simply does not mention is reported too, but as informational: it is not a schema violation, but it is very often exactly the mistake it looks like, and the alternative -- staying silent the way helm lint does -- is how the typo ships.

It reads plain YAML and JSON text with its own parser -- no Helm binary, no chart dependency resolution (Chart.yaml's dependencies are not walked), no cluster, no network call. That is what makes it safe to run against a chart repository with nothing installed and no credentials granted at all.

What this is not

This is not a replacement for helm lint or helm template -- it does not read chart templates, Chart.yaml metadata, or subchart dependency resolution at all, and a values file that matches its schema perfectly can still render a broken chart for reasons entirely outside values.yaml. It is also not a full JSON Schema implementation: it understands type, properties, required, additionalProperties, enum, minimum/maximum, and items, not $ref, oneOf/anyOf/allOf, or regex pattern. See how this differs from helm lint for exactly where each tool's coverage stops.

Common questions

What actually happens when a chart template reads a values.yaml key that isn't set?

Go's text/template and html/template packages, which Helm renders through, return the zero value for a missing map key rather than an error -- an empty string for .Values.image.repository if it was never set. The template renders successfully with a blank or a chart default standing in for whatever the typo'd key should have provided, and nothing about the render itself signals that anything went wrong.

Why doesn't helm lint catch this?

helm lint validates values.yaml against values.schema.json only if the chart ships one, and even then only enforces additionalProperties: false if the schema author set it -- JSON Schema's default is to allow fields it does not mention. Most real charts' schemas do not set it, so a field values.yaml sets that the schema never declares -- exactly the shape a typo takes -- is not a schema violation at all, and lint says nothing about it.

Does the required: true option in values.schema.json help?

It helps with a different half of the same problem. required catches a key the schema expects that values.yaml never sets at all. It does not catch the reverse: a key values.yaml does set, under a name the schema does not recognize, sitting right next to the correctly-named one it was supposed to override. Both are worth checking, and this tool checks both.