In an 18-chart Helm umbrella release, two subcharts each `define` a named template `labels` — what happens?
answer
- Names are not scoped to a chart
- One set for the whole release
- Duplicates overwrite instead of erroring
- Load order decides, so never rely on it
- Prefix every definition with the chart name
basics
~20 sNamed templates are global to the release, not scoped per chart: the parent and every subchart load into one namespace. Two definitions of the same name do not conflict loudly — whichever loads last wins, and both charts silently render it.
solid answer
~50 sWhen Helm loads a chart it collects the template files of the parent and of every subchart into a single template set, so a name defined anywhere is callable from anywhere and a duplicate name is simply overwritten. There is no error and no per-chart scoping: whichever definition is loaded last is the one both charts use, so one subchart's Deployment quietly comes out wearing another subchart's labels. That is the whole reason the convention is to prefix every name with the chart name — `scoring-api.labels`, not `labels`. Diagnose it by rendering the umbrella and reading the object that looks wrong, then searching the unpacked chart tree for every definition of that name; the fix is to rename both, chart-prefixed. Where several charts genuinely need the same helper, share it deliberately through a chart of definitions rather than by relying on the shared namespace.
code
yaml · 11 lines{{/* charts/scoring-api: prefixed, so it cannot be overwritten */}}
{{- define "scoring-api.labels" -}}
app.kubernetes.io/name: scoring-api
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/* charts/scoring-worker: a different name, a different definition */}}
{{- define "scoring-worker.labels" -}}
app.kubernetes.io/name: scoring-worker
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}go deeper
Take away the habit: give every named template a name that starts with your chart's name and a dot, because names are shared across the whole release rather than kept per chart.
Be able to explain the mechanism — parent and subchart templates load into one set, a duplicate name overwrites rather than errors, and visibility runs in both directions between parent and dependency.
Show the diagnosis: render the umbrella, read the wrong object, search the unpacked dependency tree for every definition of that name, and confirm by renaming one. Say explicitly that load order is not a contract to reason from.
Own the prevention across an estate: a lint rule on definition names, a deliberate way to share genuinely common helpers with a pinned version, and a policy on whether shadowing a dependency's helper is ever an acceptable patch.
## One namespace for the whole release A Helm release renders as a single template execution. Helm walks the parent chart and every dependency under it, parses every template file it finds, and registers every `define` into one shared set of named templates. The chart a definition came from is not part of its identity — only the name is. That has two consequences people rarely expect until it bites. The first is that visibility is total. A parent's manifest can call a helper defined only in a subchart, and a subchart's manifest can call one defined only in the parent. Nothing enforces a boundary, so a chart can grow an invisible dependency on a helper that belongs to something else, and the day that dependency is upgraded and the helper is renamed, the chart that borrowed it breaks with an error about a template that is not associated with the render. The second is that duplicates do not conflict — they overwrite. Register `labels` twice and the second registration replaces the first; whichever file is loaded last wins, and both charts then render the surviving definition. There is no warning, no error, and no per-chart copy. On an 18-chart umbrella that means a scoring API's Deployment can come out carrying the fraud-scoring worker's `app.kubernetes.io/name`, which is worse than a failed render: selectors match the wrong pods, dashboards and alerts group the wrong series, and a Service can end up in front of another chart's workload. ## Why prefixing is the convention, not a style preference This is the reason every generated chart names its helpers `<chart>.fullname`, `<chart>.labels`, `<chart>.selectorLabels` rather than `fullname` and `labels`. The prefix is a poor man's namespace: it makes the flat set behave as though each chart had its own. The rule is easy to state and easy to review — every `define` in a chart begins with that chart's name and a dot — and it removes the entire class of collision. The rule matters most for the generic names, because those are the ones two independent authors will both reach for: `labels`, `name`, `image`, `env`, `annotations`, `resources`. A subtlety worth knowing: the prefix is only a convention. Nothing in Helm derives it from `Chart.yaml`, nothing validates it, and renaming a chart does not rename its helpers. A chart that is vendored, forked or aliased keeps whatever names its `define` blocks carry. ## Diagnosing a live collision The symptom is a rendered object that is wrong in a way its own chart cannot explain. Work from the output backwards: 1. Render the umbrella and look at the offending block in the produced manifest. Two objects from different subcharts emitting the same labels, or a name from the wrong chart, is the tell. 2. Search the chart tree — including the packaged dependencies under the chart's own `charts/` directory, not just your source — for every definition of that name. Two hits in two charts confirms it. 3. Confirm by rendering the umbrella with the suspect subchart's dependency disabled, or by temporarily renaming one of the two definitions and seeing the output change for both objects. Do not try to reason about which one wins from load order. The order is an implementation detail of how the chart tree is walked, it is not a contract, and a chart that depends on it is broken whether or not it currently renders correctly. ## Fixing it, and preventing it The fix is to rename both definitions with chart-scoped names and update the call sites. It is mechanical and safe, because the names have no meaning outside the render. Prevention is a review rule plus, if you own a lot of charts, a lint check that fails any `define` whose name does not start with the chart's name and a dot. That check is cheap and catches the problem at authoring time rather than in a rendered umbrella. Where several charts really do need the same helper, the answer is to share it on purpose — through a dependency whose whole job is to carry those definitions — rather than by leaning on the shared namespace and hoping the names do not clash. Deliberate sharing gives you a version to pin and one place to change the helper; accidental sharing gives you neither, and the failure mode is a chart that renders differently depending on which other charts happen to be installed alongside it.
- Can a parent chart deliberately override a helper that a subchart defines?Yes — since it is one namespace, defining the same name in the parent can replace the subchart's version for the whole release. It occasionally gets used to patch a dependency you cannot change, but it is fragile: which definition wins depends on load order rather than on any documented rule, and the next upgrade of that dependency can silently change the outcome. Prefer values the subchart exposes, or a post-render step, over name shadowing.
- How would you stop this class of bug across a large chart estate?Make it a lint rule: fail any `define` whose name does not begin with its chart's name and a dot, and run it in the chart repository's CI. That catches the collision at authoring time instead of in a rendered umbrella. Pair it with a review habit of searching the unpacked dependency tree — not just your own source — whenever a helper name looks generic, because vendored dependencies carry whatever names their authors chose.
saying these in an interview costs you the question
- Assumes each chart gets its own template namespace
- Expects Helm to fail on a duplicate definition
- Names helpers labels or fullname with no chart prefix
- Believes the parent chart's definition always wins
- Thinks values or aliases isolate colliding helper names