Engineers: Stop 2 AM Rollouts with Helm Values Validation & CI
Practical steps for engineers to enforce Helm values validation with values.schema.json and chart‑testing CI. Catch bad configs in PRs and avoid 2 AM...
Helm validates chart input by applying values.schema.json (JSON Schema) to the final merged .Values during helm install, upgrade, lint, and template. Combine that with chart-testing scenarios in CI to catch configuration errors before they reach a cluster. Add the schema at the chart root, wire it into your pipeline, and most bad values get caught at review time instead of 2 AM.
TL;DR:
- Helm validates the merged
.Valuesobject againstvalues.schema.jsonduring install, upgrade, lint, and template commands, including subcharts with their own schemas.- The schema must reside at the chart root and include
$schema, type definitions, properties, required keys, andadditionalPropertiesto be effective.- YAML coercion can cause validation errors; quote version and port strings to prevent unintended type changes, and use JSON Schema’s
if,then,elsefor conditional logic.- Validation fails early if remote
$reflinks are used; vendor schemas into the chart to avoid unreachable references, especially in air-gapped environments.- Integrate chart-testing in CI to catch schema, structural, and deployment errors across multiple scenario files before releasing to production.
Table of Contents
- How Helm’s values validation actually works
- Create values.schema.json: minimal structure and placement
- JSON Schema features and Helm-specific nuances to use
- Subcharts, parent overrides, and how validation propagates
- Validate values in CI: chart-testing and installation tests
- Common pitfalls, operational trade-offs, and fixes
- Step-by-step example: add a schema, test locally, and validate in CI
- Verify and debug validation errors: commands and typical error messages
- Practical checklist for hardening charts in production
- When schema validation is worth the maintenance cost
- How DevOps AI Toolkit helps you harden Helm charts
- Sources
- FAQ
How Helm’s values validation actually works
Here’s the part people get wrong: Helm doesn’t validate your values.yaml file in isolation. It validates the final .Values object, the one assembled after merging chart defaults, parent overrides, --set flags, and any -f files you passed on the command line. If that merged result doesn’t satisfy values.schema.json, Helm stops before rendering templates.
According to the Helm project’s own documentation, this validation kicks in on four commands:
helm install, when you’re standing up a release for the first timehelm upgrade, when you’re changing an existing release’s valueshelm lint, when you’re checking a chart before packaging or committing ithelm template, when you’re rendering manifests locally or in a CI dry run
Subchart schemas get enforced too. If a dependency chart ships its own values.schema.json, the portion of your merged values that maps to that subchart has to satisfy it, regardless of what the parent chart’s schema says. There’s also a --skip-schema-validation flag, added specifically for cases like air-gapped clusters where a schema references a remote resource Helm can’t reach. It’s a valid escape hatch, but it’s not something you want baked into a normal deploy path, since it removes the one automated check standing between a typo and a broken rollout.
Create values.schema.json: minimal structure and placement
Helm looks for values.schema.json in one place: the chart root, next to Chart.yaml and values.yaml. No configuration flag points Helm at it. If it’s not there, Helm skips schema validation entirely and falls back to whatever defaults your templates handle gracefully, or don’t.
A working minimal schema needs four things:
$schema, declaring which JSON Schema draft you’re targeting, usuallyhttp://json-schema.org/schema#or a specific draft URLtype: object, since.Valuesis always a map at the rootproperties, one entry per key you want validated, each with its owntypeand constraintsrequiredandadditionalProperties, controlling which keys must exist and whether unlisted keys are tolerated
Here’s a schema for a chart with a replica count and a service port:
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1
},
"service": {
"type": "object",
"properties": {
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["port"]
}
},
"required": ["replicaCount", "service"]
}
Map every property directly to its path in values.yaml, nesting objects the same way you nest your YAML. Keep schemas maintainable by matching the chart best practices recommendation to document every value you expose: a comment above each values.yaml entry describing its purpose and type makes the schema easier to keep in sync when someone adds a field six months from now and forgets the schema exists.
JSON Schema features and Helm-specific nuances to use
JSON Schema is strict about types in a way YAML is not, and that gap causes more validation headaches than anything else. YAML happily interprets port: 8080 as an integer and enabled: yes as a boolean, but it can also coerce things you didn’t intend, like turning an unquoted version string 1.20 into a float and dropping the trailing zero. Quote any value that’s meant to stay a string, especially version numbers, ports written as strings, and anything with a leading zero.
additionalProperties decides how strict your schema is:
- Set it to
falseon an object to reject any key that isn’t explicitly listed, useful for public or platform charts where you want tight control over input. - Leave it unset or
truewhen a chart is still evolving and you’d rather not block contributors adding new optional fields. - Apply it selectively: strict at the top level, permissive on a nested block you know will grow.
For mutually exclusive configuration, like choosing between “use an existing secret” or “create one from provided fields,” JSON Schema’s conditional keywords let you express that relationship directly with if, then, and else, instead of relying on template logic to catch the conflict at render time.
One more nuance: avoid remote $ref pointers in a chart schema when you can. A schema that pulls in a definition from an external URL will fail validation the moment that URL is unreachable, which is exactly the air-gapped scenario that made --skip-schema-validation necessary in the first place. Vendor the referenced schema into your chart repository instead.

Pro Tip: Run helm template --debug after every schema change. It renders faster than a full install and shows you the merged values Helm actually validated, not what you assumed it would.
Subcharts, parent overrides, and how validation propagates
Chart dependencies complicate validation in a way that trips up a lot of teams the first time they hit it. The rule, confirmed by Helm’s own test suite and issue tracker, is straightforward: the final .Values object is checked against every schema in the dependency tree, and a parent chart cannot override or bypass a subchart’s schema requirements. If a subchart requires postgresql.auth.password to be a non-empty string, setting it to an empty string from the parent chart’s values.yaml still fails, no matter what the parent’s own schema allows.
Practical patterns that keep this from becoming friction:
- Mirror the subchart’s expected structure exactly in your parent
values.yamlcomments, so anyone editing the file can see which keys belong to which dependency. - Test parent overrides against the subchart’s schema locally with
helm templatebefore assuming an override will work in CI. - Pin subchart versions in
Chart.yamlso an upstream schema change doesn’t silently break your parent chart’s deployments.
When a subchart’s schema genuinely conflicts with how your platform needs to configure it, vendoring the subchart into your own repository or wrapping it with a thin adapter chart is often less painful than fighting the upstream schema on every release. Platform teams managing several internal charts on top of community subcharts do this specifically to keep schema expectations aligned across the dependency graph, since Helm’s validation behavior makes it clear there’s no other way to relax a subchart’s own requirements.
Validate values in CI: chart-testing and installation tests
Schema validation catches structural problems: wrong types, missing keys, disallowed fields. It won’t catch a combination of otherwise-valid values that breaks your application at runtime. That’s what chart-testing (ct) is for, and it’s the piece most teams skip until a bad combination reaches production.
A solid ct-based pipeline looks like this:
- Detect changed charts.
ctidentifies which charts changed in a pull request by default, so you’re not re-testing your entire chart repository on every commit. - Lint per values file.
ct lintrunshelm lint,yamllint, and chart-specific checks against every file matching a convention likeci/*-values.yaml, so a single chart can be tested against several realistic configurations, not just its defaults. - Install-test each scenario.
ct installspins up a real (or kind-based) cluster and installs the chart using each of those same values files, catching problems that only surface once Kubernetes actually tries to reconcile the resources. - Layer in template dry runs. Running
helm templateandhelm install --dry-runagainst each scenario file adds a fast pre-check before the fullct installcycle, useful for catching schema errors in seconds instead of waiting on a cluster spin-up.
A repeatable setup that works well ties per-PR ct lint to every changed chart, runs a matrix job for ct install against your essential scenario files (staging config, high-availability config, minimal config), and gates merges on both passing. According to chart-testing’s documentation, this per-values-file approach is built into ct specifically because validating only a chart’s default values.yaml misses the configurations teams actually run in production.
Common pitfalls, operational trade-offs, and fixes
Most schema validation failures fall into a handful of repeat offenders. Knowing the pattern makes them faster to diagnose.
- Remote
$reffailures in air-gapped environments. A schema referencing an external URL fails the moment that URL isn’t reachable. Vendor the reference into your chart repository, or isolate the exception behind a documented flag rather than disabling validation chart-wide. - Overuse of
--skip-schema-validation. The flag exists for a reason, specifically air-gapped clusters where remote references can’t resolve, but it should be an audited, logged exception, not a routine fix for “the schema is annoying.” If your CI pipeline uses it by default, you’ve quietly turned off your safety net. - YAML type coercion surprises. Unquoted values that look like numbers or booleans get coerced by the YAML parser before Helm’s schema even sees them. Quote strings explicitly, and where a template needs to normalize a value, Sprig template functions handle the conversion more predictably than hoping the YAML parser guesses right.
- Schemas too strict too early. A brand-new chart with a locked-down schema slows down the exact experimentation it needs in its first few weeks. Start permissive, tighten
additionalPropertiesandrequiredas the chart stabilizes, and enforce the stricter version in CI once the interface is settled.
Pro Tip: Keep a short changelog entry every time you tighten a schema. The next engineer who hits a validation failure will want to know if it’s a new rule or a bug in their values file.
Step-by-step example: add a schema, test locally, and validate in CI
Here’s the full loop, from a bare chart to a CI-gated one.
- Write a minimal
values.yaml. Something likereplicaCount: 2,server.port: 8080, andfeature.enabled: falsecovers the common case: a count, a network setting, and a toggle. - Write the matching
values.schema.json. DeclarereplicaCountas an integer with a minimum of 1,server.portas an integer between 1 and 65535, andfeature.enabledas a boolean, then mark all three required withadditionalProperties: falseat each object level. - Verify locally. Run
helm lint .first, since it’s the fastest feedback loop. Follow withhelm template .to see the rendered manifests, thenhelm install my-release . --dry-run --debugto confirm the merged values Helm would actually use in a real install. - Add CI scenario files. Create
ci/default-values.yaml,ci/high-availability-values.yaml, andci/minimal-values.yaml, each representing a real deployment shape your chart supports. - Wire up
ctin your pipeline. Runct lint --config ct.yamlto check every scenario file against the schema, thenct install --config ct.yamlto confirm each one deploys cleanly. - Read failures and fix both sides. A schema error naming a field that shouldn’t exist usually means either the scenario file has a typo or the schema is stricter than it should be. Fix whichever one is wrong, then re-run before committing.
This loop is quick once it’s set up. The setup cost is a values file, a schema file, and a ct.yaml config, and it pays for itself the first time someone’s --set typo gets caught in a pull request instead of a rollout.
Verify and debug validation errors: commands and typical error messages
When validation fails, helm lint and helm template give you the fastest read on what broke and where.
- “expected integer but got string” usually means an unquoted or misformatted value in your values file, or a
--setflag that passed a string where the schema wants a number. - “missing required property” points to a key the schema requires that’s absent from your merged values, often because a subchart’s schema requires something the parent chart never set.
- “additionalProperties not allowed” flags a key that doesn’t exist in the schema at all, commonly a typo or a leftover field from a previous chart version.
- Run
helm install --dry-run --debugwhen the error’s source isn’t obvious. It prints the fully merged values, including everything contributed by subcharts, so you can see exactly what Helm validated.
Once you fix a validation error, update both the schema and your ci/*-values.yaml scenario files, so the same mistake gets caught automatically next time.
Practical checklist for hardening charts in production
Generating a schema by hand for a chart with dozens of values is tedious, and AI-assisted generation has become a practical shortcut for getting a first draft fast, an approach covered in more depth in generating values.schema.json with AI. The output still needs a human pass to confirm required fields and type constraints match what the chart actually expects, but it beats writing 40 properties from scratch.
Pair that with a pre-merge testing habit, outlined in testing Helm charts before they reach production, and a working checklist looks like this:
- Run
ct lintagainst every scenario file before merging, not just the default values. - Run
helm templatefor each target environment (staging, production, disaster recovery) to catch environment-specific schema mismatches. - Block
--skip-schema-validationfrom protected branch pipelines, and require a documented reason whenever it’s used elsewhere.
When schema validation is worth the maintenance cost
Schemas aren’t free. Writing and maintaining values.schema.json for a chart nobody else touches is often wasted effort. But for platform charts, anything shared across teams, or anything published for external users, a strict schema turns a vague deployment failure into a specific, readable error message before a single pod gets scheduled. That trade favors strict validation every time you can’t personally vouch for who’s setting the values.
For a chart still in active development, a permissive schema (or none yet) lets you iterate without fighting your own guardrails. The moment that chart stabilizes or gets a second user, tighten it and enforce it in CI with an audited skip process rather than an open one. Teams that need help building that pipeline can find audit and consulting options at DevOps AI Toolkit.
— James
How DevOps AI Toolkit helps you harden Helm charts

Writing a correct schema is one afternoon of work. Catching every place your charts, values files, and CI pipeline disagree with each other is the part that actually eats a week, and it’s the part a fresh set of eyes tends to catch faster than the team that’s been staring at the chart for months. A Kubernetes Health Check for $300 gives you a focused review of your chart’s schema coverage, values structure, and where validation gaps are letting bad input through. If your validation problems are tangled up with broader infrastructure code, a Terraform / IaC Audit at $250 covers that ground too.
For teams that want to build the schema and CI habit themselves, the site also runs a Docker Academy Individual Pro membership at $19 per month, plus a library of AI prompt packs and troubleshooting guides for the rest of the Kubernetes and Helm workflow. Check current plans on the pricing page, or book a review directly through the work-with-me page if you’d rather have someone else find the gaps first.
Sources
- chart-testing (ct) documentation
- feat(helm): add —skip-schema-validation flag to helm ‘install’, ‘uprade’ and ‘lint’
- Understanding JSON Schema: conditionals
FAQ
How do I get all values from a Helm chart?
Run helm show values <chart> to see a chart’s default values.yaml before installing it, or helm get values <release> to see the values currently applied to a deployed release. Add --all to helm get values to include values inherited from the chart’s own defaults, not just the ones you explicitly set.
How do I update values in a Helm chart?
Edit your values file or pass --set key=value on the command line, then run helm upgrade <release> <chart> -f values.yaml to apply the change. Helm validates the newly merged values against values.schema.json as part of that upgrade, so a bad edit gets caught before it reaches your cluster.
Is Helm deprecated?
No. Helm remains an actively maintained project under the CNCF, with ongoing feature work, including the --skip-schema-validation flag added in a 2024 pull request. It’s the standard packaging tool for Kubernetes applications and continues to receive regular releases.
What is the order of precedence for values in a Helm chart?
Helm applies values in layers, with each layer overriding the one before it: chart defaults from values.yaml, then parent chart values for subcharts, then -f files in the order they’re passed, then --set and --set-string flags last. The final merged result from all these layers is what gets validated against values.schema.json.
Where does Helm’s schema file need to live?
Helm looks for values.schema.json at the root of the chart directory, next to Chart.yaml and values.yaml. If it’s missing, Helm skips schema validation for that chart entirely, though subchart schemas still apply to their portion of the merged values.
Recommended
- Common Helm Chart Deployment Errors: Fix Them Fast
- Testing Helm Charts Before They Reach Production
- GitLab CI + Helm: Repeatable Kubernetes Deploys Without the
- Automating Helm Chart Deployments: A DevOps Guide
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.