skip to content

A helm upgrade fails with 'no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"' — what is the cluster telling you?

level: juniorimportance: should knowfreq 58%

answer

  1. The document parsed; something else failed
  2. Helm asks the API server what exists
  3. Two manifests can carry the bad version
  4. Rendered chart versus stored release manifest
  5. helm template and helm get manifest

basics

~10 s

The cluster no longer serves that apiVersion, so Helm cannot map the kind to any resource the API server offers. Some manifest Helm is reading still names networking.k8s.io/v1beta1, which the upgraded cluster dropped.

solid answer

~50 s

This is a **mapping** failure, not a YAML failure. Helm turns every `apiVersion` + `kind` pair into a REST path by consulting the API server's discovery data; when the group/version is not in that list, the mapper returns `no matches for kind ... in version ...`. The document parsed fine — the cluster simply has no such API any more, because it was upgraded past a Kubernetes release that retired the beta version. Two manifests can carry the offending text: the one your chart just rendered, or the one **stored with the existing release** from when it was first installed. Helm's wording tells you which side failed — a failure building objects from the *current release manifest* is the stored copy. Confirm with `helm get manifest <release> -n <ns> | grep networking.k8s.io` and compare against `helm template` on the chart you are about to ship.

code

bash · 8 lines
bash
helm upgrade fraud-scoring ./platform -n payments
# ... no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"

# is it what I am about to ship?
helm template ./platform -n payments | grep -n 'networking.k8s.io'

# or what the release already stored?
helm get manifest fraud-scoring -n payments | grep -n 'networking.k8s.io'

go deeper

for a junior

Recall that this sentence means the cluster does not serve that apiVersion at all — the YAML is fine. Know the two commands that show you which manifest carries it: helm template for the render, helm get manifest for the stored one.

for a middle

Explain that Helm resolves apiVersion and kind through the API server's discovery data, and that the identical message also means a missing CRD. Be able to say why the running object stays healthy while Helm's copy of the text does not.

for a senior

Show the triage order: grep both manifests before touching anything, since a chart bump fixes one case and does nothing for the other. Mention upgrading releases ahead of an API removal as the cheap prevention.

for a principal

Own the timing argument — the window before a version is retired is when this costs one routine upgrade, and after it is retired the same fix needs a release repair on every affected release across the estate.

### Where the sentence comes from Every Kubernetes client — `kubectl`, a controller, and Helm alike — has to turn the pair (`apiVersion`, `kind`) written at the top of a manifest into a concrete REST endpoint. It does that by fetching the API server's discovery document, which lists every group/version the cluster currently serves and the resources inside each, and building a mapper from it. The string `no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"` is what that mapper returns when the group/version it was handed is not in the list. That matters for how you read the error. Nothing is malformed. The YAML parsed, the indentation is fine, the field names are spelled correctly, and RBAC never entered the picture — Helm never got as far as making a request. The cluster simply has no `networking.k8s.io/v1beta1` endpoint to talk to, because a Kubernetes release retired that beta group/version and the cluster has since been upgraded onto it. Beta APIs are removed on a published schedule; the day someone upgrades the cluster is the day any manifest still naming the beta version stops resolving. ### The other cause of the same sentence The identical message appears for an unrelated reason: a custom resource whose CustomResourceDefinition is not installed. Helm's message often appends a hint about ensuring CRDs are installed first, which sends people hunting for a missing operator when the real cause is a retired built-in API. Read the group inside the quotes to tell them apart. A well-known Kubernetes group with a beta suffix on a kind you recognise as built-in — `networking.k8s.io/v1beta1` for `Ingress`, `policy/v1beta1` for `PodDisruptionBudget`, `batch/v1beta1` for `CronJob` — is a retired built-in, and the fix is a newer `apiVersion`. A vendor group you do not recognise on a kind you do not recognise is a missing CRD, and the fix is installing the operator that owns it. ### Which manifest is at fault Helm reads two manifests during an upgrade: the one it renders from the chart you passed, and the one it stored when the release was last installed or upgraded. Both are plain text; either can name a version the cluster no longer serves. Distinguishing them is the whole job on this error, because the repairs are completely different. If the **new render** is at fault, the chart is out of date and the fix is a chart bump — a newer chart version that emits the supported `apiVersion`. You can see it without touching the cluster: ``` helm template ./platform -n payments | grep -n 'networking.k8s.io' ``` If the **stored manifest** is at fault, the chart may already be perfect and the upgrade still fails, because Helm has to decode the previous release's manifest before it can work out what changed. That copy is frozen at the text it was written with and nothing rewrites it retroactively — not the API server, not a later `helm repo update`, not the fact that the live object is perfectly healthy. You see it with: ``` helm get manifest fraud-scoring -n payments | grep -n 'networking.k8s.io' ``` The live object being fine is the part that confuses people. When a cluster stops serving a version, the objects themselves do not disappear; the API server keeps serving them under a version it still supports, and `kubectl get ingress` works normally. Helm's problem is with its own recorded text, not with the running resource. ### What to do first Run both greps before changing anything. They cost nothing, they need no cluster write access, and between them they tell you whether you are fixing a chart or repairing a release record. If only the render is stale, upgrade the chart dependency or bump the subchart and re-run. If the stored manifest carries it, a chart bump alone will not clear the error, and you are into repairing the stored release record — rewriting the retired version inside it, or dropping the release history and re-adopting the live objects. One piece of timing advice that this error teaches better than any doc: if you know a version is about to be retired and your chart already renders the supported one, upgrade the release **now**, while the old version still resolves. The upgrade succeeds, the new revision's stored manifest carries the supported version, and the problem never happens. After the cluster has dropped the API you have the same fix plus a broken release to repair first.

  • The Ingress object is Running and kubectl get ingress works. Why does Helm still complain about a version that no longer exists?
    The API server persists an object once and serves it under whichever version it still supports, so reading it works fine. Helm's complaint is about text it holds itself — the manifest it rendered, or the manifest it stored with the release — and that text is literal. Nothing converts it when the cluster drops a version.
  • How do you tell this error apart from a missing CustomResourceDefinition, which produces the same sentence?
    Look at the group and kind inside the quotes. A core Kubernetes group with a beta suffix on a familiar built-in kind means a retired API, and the fix is a newer apiVersion. An unfamiliar vendor group on an unfamiliar kind means the CRD has not been installed, and the fix is installing the operator or chart that owns it.

saying these in an interview costs you the question

  • Says the chart's YAML is malformed or badly indented
  • Blames RBAC for a mapping error Helm never sent
  • Assumes it always means a missing CRD
  • Thinks the live object was deleted by the cluster upgrade
  • Reaches for helm repo update as the fix

context