What does helm lint check in a chart, and what does it not catch?
answer
- A check that never touches a cluster
- Three severity levels in the output
- Exit code follows the highest severity
- One flag promotes warnings to failures
- It renders only the branches your values reach
basics
~20 shelm lint parses the chart metadata, renders the templates with the values it is given, and reports INFO, WARNING and ERROR findings. It never contacts a cluster, so a manifest that renders as valid YAML but is an invalid Kubernetes object still passes.
solid answer
~40 s`helm lint` runs two kinds of rule over a chart directory or packaged `.tgz`. First the metadata rules: `Chart.yaml` exists and parses, `apiVersion` and `name` are present, the directory name matches `name`, `version` is valid SemVer, `values.yaml` parses, a `templates/` directory exists, an icon is recommended. Then it renders every template with the coalesced values and checks the output parses as YAML, flagging Kubernetes API versions it knows to have been removed. If the chart has a `values.schema.json`, the values are validated against it too. By default only an ERROR fails the run; `--strict` makes warnings fail as well. What it does not do is talk to an API server or check the rendered objects against the Kubernetes schema, and it only renders the branches the values you passed actually reach.
code
bash · 3 lineshelm lint ./charts/fanout-operator --strict
helm lint ./charts/fanout-operator --strict -f ci/metrics-enabled-values.yaml
helm lint ./charts/fanout-operator --strict --with-subchartsgo deeper
Be ready to say what the command is for in one breath: it renders the chart and reports metadata and template problems, without a cluster. Know that errors fail it and warnings do not unless you ask for that.
Explain the mechanics: the metadata rules, the render step, the YAML parse of the output, the schema check, and the three severities mapped onto the exit code. Say plainly which classes of defect are outside its reach.
Show how you wire it into a pull request: strict mode, one run per supported values file, subcharts included, and a clear account of what still needs a render-assertion step or a cluster behind it.
Own the boundary. Argue what a syntax-level check is worth in a chart that many teams install, where you spend the next unit of effort, and how you keep a green lint from being mistaken for a release-readiness signal.
## What lint is, and what it is not `helm lint` is a static check over chart *source*. You point it at a chart directory or a packaged `.tgz` (`helm lint ./charts/fanout-operator`) and it applies a fixed set of rules, printing findings at three severities and a one-line summary of how many charts were linted and how many failed. It is the cheapest gate a pull request can run: no cluster, no credentials, no container, milliseconds. It is emphatically not `helm test`. That command installs nothing and asserts nothing on its own; it runs test-annotated Pods against a release that is already installed in a cluster. Lint is the opposite end of the pipeline — it runs before anything exists. ## The rules it applies Roughly two families. **Chart-shaped rules.** `Chart.yaml` must exist and parse; `apiVersion` and `name` must be present; the directory the chart lives in must have the same name as the `name` field; `version` must be valid SemVer; `values.yaml`, if present, must parse as YAML; a missing `templates/` directory is reported; a missing `icon` is an informational nudge, not a failure. **Render rules.** Lint actually renders the chart. Every file under `templates/` is executed as a Go template against the coalesced values, and the output is parsed as YAML. A missing function, a bad pipeline, an `index` into a nil value, a `required` helper that fires, unbalanced indentation that produces unparseable YAML — all of these surface here as errors, and they are the findings lint is genuinely good at. Lint also compares the `apiVersion`/`kind` pairs in the rendered output against a list of Kubernetes API versions it knows to have been removed, so a chart still emitting a long-dead API version gets flagged. **Values-schema rules.** If the chart ships a `values.schema.json`, lint validates the coalesced values against it before rendering, so a wrong type or a missing required key fails at lint time rather than at install time. ## Severities and exit codes Findings print as `[INFO]`, `[WARNING]` or `[ERROR]`. By default the command exits non-zero only when at least one ERROR was reported — warnings are advisory. `--strict` promotes warnings so that they fail the run too, which is what you normally want in CI once a chart is clean. `--quiet` suppresses the informational chatter and prints only warnings and errors. ## The values you pass are the coverage you get This is the part candidates miss. Lint renders with the values it has: the chart's own `values.yaml` plus anything you supply with `-f`, `--set`, `--set-string` or `--set-file`. A template body wrapped in `{{- if .Values.metrics.enabled }}` where the default is `false` is never executed, so a syntax error inside it is invisible to a default lint run and ships to whoever turns the flag on. The practical consequence is that lint is run once per supported values combination, not once per chart. Similarly, `--with-subcharts` is needed for the metadata rules to be applied to each dependency under `charts/` as its own chart. Files under `crds/` are never templated at all, so nothing in your values changes them and nothing lint does exercises them. ## What it cannot catch Everything downstream of *is this valid YAML*. Lint has no Kubernetes object schema, so `replicas: three` in a Deployment, a misspelled `contaienrs` key, a Service `targetPort` that no container exposes, a name longer than the 63 characters Kubernetes allows for a Service, a selector that matches nothing — none of them are lint findings. It cannot see the cluster's real Kubernetes version or its installed CRDs, cannot know whether an image tag exists, and has no opinion about whether the resulting workload would ever become ready. That gap defines the rest of a chart's pre-merge suite: lint proves the chart renders, a values schema proves the inputs are shaped correctly, assertions over `helm template` output prove the rendered objects say what you meant, and only a server-side dry run or a real install proves the API server will accept them. ## Using it in CI Run it per values file, with `--strict`, as the first step — it is fast and its failures are unambiguous. Treat a clean lint as a statement about syntax and metadata, never as a statement about correctness.
- What does --with-subcharts change about a helm lint run?It lints each dependency under `charts/` as a chart in its own right, so the metadata and values rules are applied to them too. Without it you get findings only for the parent chart, even though rendering the parent already renders the subcharts' templates as part of the output.
- Does helm lint tell you anything about the files in crds/?Very little. Files in `crds/` are plain YAML that Helm never templates, so the render rules never exercise them and your values cannot change them. They are also left out of `helm template` output unless you pass `--include-crds`, which is why a render-assertion job on an operator chart often reports zero CRDs until someone notices the flag.
- Your lint is green and a colleague's run on the same commit fails. What differs?Almost always the values. Lint renders what it is given, so a different `-f` file, a stray `--set`, or `--strict` on one side and not the other changes which templates are executed and which severities fail the run. Pin the values files and the flags in the repository so every run is the same run.
Lint is the spell-checker on a contract: it catches a misspelling and a missing signature block, and has nothing to say about whether the clauses mean what you intended.
saying these in an interview costs you the question
- Thinks helm lint validates manifests against the Kubernetes API
- Believes lint fails on warnings by default
- Assumes lint covers templates the default values never render
- Confuses helm lint with helm test against a live release
- Thinks lint inspects dependencies without being asked
- Calls a green lint proof that the chart installs