The Error
error: unable to recognize "deploy.yaml": no matches for kind "Ingress" in version "extensions/v1beta1"
You ran kubectl apply -f against a Kubernetes 1.22+ cluster and it blew up β even though the YAML looks perfectly fine. The problem isn't your syntax. It's that the API version in that file no longer exists on the cluster.
Root Cause
Kubernetes 1.22 deleted the extensions/v1beta1 API group entirely. Not deprecated β deleted. The API server has no record of what an Ingress under that group means, which is exactly what "no matches for kind" is telling you.
The Ingress API went through three generations before this happened:
- β€ 1.13: Only
extensions/v1beta1available - 1.14:
networking.k8s.io/v1beta1introduced;extensions/v1beta1marked deprecated - 1.19:
networking.k8s.io/v1promoted to stable - 1.22: Both beta versions axed β this is when the error starts appearing
Worth noting: Deployment, DaemonSet, and ReplicaSet under extensions/v1beta1 were already cut in 1.16. Multiple resource types failing at once usually means your manifests originate from Kubernetes 1.14 or earlier.
Fix: Update the Manifest
Changing the apiVersion line alone won't cut it. The networking.k8s.io/v1 Ingress spec restructured the backend field and made pathType required. Three things need to change.
Old (extensions/v1beta1 β broken on 1.22+)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 80
New (networking.k8s.io/v1 β works on 1.19+)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Here's exactly what moved:
backend.serviceNameβbackend.service.namebackend.servicePortβbackend.service.port.number(or.namefor named ports)pathTypeis now required β usePrefix,Exact, orImplementationSpecific
Bulk Migration with kubectl-convert
Got dozens of manifests to update? The kubectl-convert plugin handles the conversion automatically instead of forcing you to edit each file by hand:
# Install the plugin (Linux)
curl -LO "https://dl.k8s.io/release/$(kubectl version --client -o json | jq -r .clientVersion.gitVersion)/bin/linux/amd64/kubectl-convert"
chmod +x kubectl-convert
sudo mv kubectl-convert /usr/local/bin/
# Preview the converted output
kubectl convert -f old-ingress.yaml --output-version networking.k8s.io/v1
# Save to a new file
kubectl convert -f old-ingress.yaml --output-version networking.k8s.io/v1 > new-ingress.yaml
Before a cluster upgrade, run pluto to scan your entire repository for deprecated API usage in one shot:
# Install pluto (macOS)
brew install FairwindsOps/tap/pluto
# Scan all YAML files in a directory
pluto detect-files -d ./k8s/
# Check what's currently running in the live cluster
pluto detect-all-in-cluster
Verify the Fix
First, confirm your cluster actually exposes the target API:
kubectl api-versions | grep networking
# Should include: networking.k8s.io/v1
Apply the updated manifest and inspect the result:
kubectl apply -f deploy.yaml
# Expected output: ingress.networking.k8s.io/my-ingress created
kubectl get ingress my-ingress
kubectl describe ingress my-ingress
One catch: if this Ingress was previously deployed under the old API, the cluster may still hold the stale object. Delete it first, then re-apply:
kubectl delete ingress my-ingress
kubectl apply -f deploy.yaml
Prevention
- Add
pluto detect-files -d ./k8s/to your CI pipeline β it flags deprecated API versions before they ever touch a cluster. - Before upgrading, read the Kubernetes API deprecation guide for the target version. Every removal is listed there explicitly.
- When editing YAML by hand, paste it into ToolCraft's YAML β JSON Converter to catch structural problems early. It runs entirely in the browser β nothing leaves your machine β which matters when manifests contain cluster credentials or internal hostnames.
- On any unfamiliar cluster, run
kubectl api-resources | grep ingressbefore deploying so you know exactly what's available.

