skip to content

Which Helm commands enforce values.schema.json, and what exactly is validated?

level: middleimportance: should knowfreq 46%

answer

  1. Validation happens before anything renders
  2. Four commands apply it, two run pre-merge
  3. It sees merged values, not just your file
  4. A chart default can satisfy a required key
  5. A quoted number fails an integer rule

basics

~20 s

Helm applies a chart's values.schema.json during install, upgrade, lint and template. It validates the final coalesced values — chart defaults merged with every -f file and --set — before any template is rendered, not the user's own file in isolation.

solid answer

~50 s

The schema is enforced at four points: `helm install`, `helm upgrade`, `helm lint` and `helm template`. What it sees is the **coalesced** values object: the chart's `values.yaml` defaults merged with each `-f` file in order and then with `--set` overrides. Two consequences follow. A key marked `required` is satisfied by a chart default, so the schema cannot force a caller to supply something the chart already defaults. And because validation runs before rendering, a schema failure is reported instead of, not alongside, whatever template error would have followed. Type rules are where it earns its keep: `--set-string replicaCount=4` produces a string and a `type: integer` rule rejects it immediately. A subchart's own schema validates that subchart's values subtree. What the schema never validates is the *output* — it constrains inputs, not the Kubernetes objects those inputs render into.

code

json · 14 lines
json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["replicaCount"],
  "properties": {
    "replicaCount": { "type": "integer", "minimum": 1 },
    "fanout": {
      "type": "object",
      "properties": {
        "maxSubscribersPerShard": { "type": "integer", "minimum": 128 }
      }
    }
  }
}

go deeper

for a junior

Know that a chart can ship a JSON Schema for its values and that Helm checks it automatically — you do not run a separate command. Recognise the error message shape when a value has the wrong type.

for a middle

Explain the mechanics: which commands enforce it, that it sees the coalesced values, and that validation runs before rendering. Be able to say why a required key with a default never fails.

for a senior

Show how you use it as a pre-merge gate: rendering each supported values file, keeping a deliberately invalid one that must fail, and knowing which defects the schema will never catch so you place the next check correctly.

for a principal

Decide how much of a chart's contract belongs in a schema versus in documentation and template-side failures, and what it costs consumers when a schema tightens in a patch release.

## Where enforcement happens A chart may ship a `values.schema.json` beside `values.yaml`. Helm applies it during four commands: `helm install`, `helm upgrade`, `helm lint` and `helm template`. Two of those matter for a pull request — lint and template — which is what makes the schema a pre-merge check rather than only an install-time guard. A rendering job in CI therefore gets schema enforcement for free; you do not need a separate validation step to invoke it. ## What is validated: the coalesced values The single most misunderstood point is *what* the schema is handed. It is not the file the caller passed. Helm first coalesces values — the chart's `values.yaml` defaults are merged with each `-f` file in the order given, then `--set`, `--set-string` and `--set-file` overrides are layered on top — and the resulting single object is what the schema validates. Then, and only then, does rendering begin. The practical consequences: - **`required` does not mean the caller must supply it.** If `values.yaml` defaults `image.tag` and the schema lists `image.tag` as required, an install with no overrides passes: the coalesced object contains the default. To force a caller to make a decision you have to leave the key out of `values.yaml` entirely, or fail in the template with a `required` call. - **Validation precedes rendering.** A schema violation is reported and the command stops; you never see the template error that would have followed from the same bad input. This is a feature: the message points at the input the user controls rather than at line 34 of a helper they have never read. - **`additionalProperties: false` is sharper than it looks.** At the top level of a parent chart's schema it will reject the key that holds a subchart's values, because to the parent those are just more properties. ## Types, and how --set undermines them `--set` infers scalar types, so `--set replicaCount=4` yields a number. `--set-string replicaCount=4` yields the string `4`, and a `type: integer` rule rejects it — which is exactly the class of defect the schema exists to catch, because YAML and shell quoting conspire to turn numbers into strings and `true` into a string in ways that only surface as a strange rendered manifest. The same applies to a value that arrives from a CI variable and is quoted defensively on the way in. Drafts: schemas are written against JSON Schema, with draft-07 as the long-standing baseline; newer drafts have been accepted since Helm 3.18. Keep the schema to constructs you are sure the version in your pipeline understands, because a schema the CLI cannot parse is a failure of the whole command, not a skipped check. ## Subcharts A dependency that ships its own `values.schema.json` has that schema applied to its own values subtree after coalescing, so the parent's overrides of a subchart key are validated by the subchart's rules. This is genuinely useful in an umbrella chart: each component keeps its own contract instead of the umbrella's schema trying to describe everything. ## What it cannot do The schema constrains **inputs**. It says nothing about the manifests those inputs produce. A perfectly valid values object can render a Deployment with a misspelled field, a Service whose name exceeds what Kubernetes allows, or a resource that no cluster would accept. It also cannot express cross-field rules of arbitrary complexity in a way that reads well, and it cannot check that a value is *meaningful* — a registry hostname that does not resolve satisfies `type: string` all day. So the schema sits between lint and render-assertion in a chart's pre-merge suite: lint proves the templates execute, the schema proves the inputs are shaped as the chart's contract promises, and assertions over rendered output prove the objects say what you meant. Only a server-side dry run or a real install proves the API server agrees. ## A pre-merge habit Because `helm template` enforces the schema, the cheapest way to test the schema itself is to keep a directory of values files — one per supported combination, plus a couple that are deliberately invalid — and render each. The valid ones must render; the invalid ones must fail, and a schema that stops rejecting them is a regression like any other.

  • Where does a subchart's own values.schema.json apply in an umbrella chart?
    To that subchart's values subtree after coalescing, so the parent's overrides of the subchart's keys are checked by the subchart's rules. Each dependency keeps its own input contract. Watch the parent's top-level schema: if it sets `additionalProperties: false`, the key holding a subchart's values looks like an unknown property and gets rejected.
  • Why can a schema violation hide a template error that is also present?
    Because coalescing and validation both finish before rendering starts. The command fails on the first schema error and never executes the templates, so the template defect stays invisible until someone fixes the input. It is one reason to keep a values file in the repository that is deliberately invalid, and to assert that it fails for the schema reason you expect.
  • How do you make a caller supply a value that the schema alone cannot force?
    Leave the key out of `values.yaml` so the coalesced object genuinely lacks it, and mark it required in the schema; or fail in the template with the `required` function, which stops rendering with your own message. The first gives a better error earlier, the second is the fallback when the key must have a default for some paths and not others.

saying these in an interview costs you the question

  • Thinks the schema validates only the user's -f file
  • Believes a required key fails when a chart default supplies it
  • Assumes the schema validates the rendered Kubernetes objects
  • Says schema validation runs only at install time
  • Ignores that --set-string turns a number into a string
  • Expects validation to run after templates are rendered

context