What this checks
Paste one or more ----separated Kubernetes manifests and they're checked for the mistakes that kubectl apply would reject, without needing a cluster to find out. The single most useful check: a removed apiVersion. Kubernetes actually deletes old API versions on a schedule — extensions/v1beta1 and apps/v1beta1/apps/v1beta2 stopped working in 1.16, networking.k8s.io/v1beta1 and the RBAC v1beta1/v1alpha1 versions in 1.22, batch/v1beta1 (CronJob) and policy/v1beta1 in 1.25 — and a manifest written against one of these still looks completely normal until it hits a modern cluster and is flatly rejected. This also flags a kind paired with the wrong current apiVersion entirely (a Pod with apiVersion: apps/v1, for instance).
Beyond that: missing apiVersion/kind/metadata.name, a resource name that isn't valid DNS-1123 (or, for a Service specifically, the stricter DNS-1035 rule requiring it to start with a letter — Service names become part of DNS records), a Pod/Deployment/StatefulSet/DaemonSet/Job/CronJob with no containers, a missing image or duplicate container name, an out-of-range port, and the same resource (matched on kind, apiVersion, namespace, and name) defined twice in one file.
What it doesn't do
This is a structural and cross-reference check, not a full replacement for kubectl apply --dry-run=server or a real OpenAPI schema validator — it doesn't know every field of every resource type, and an unrecognized kind (a Custom Resource Definition, for example) is intentionally left alone rather than flagged, since there's no way to know its schema. Resource quantities (cpu/memory requests and limits) are checked against Kubernetes' quantity format as a warning, not an error, since that check is closer to a best-effort pattern match than the more certain apiVersion/name rules above.
FAQ
Why does an unknown kind not get flagged for its apiVersion?
Custom Resource Definitions are a first-class, completely normal part of Kubernetes, and their valid apiVersion is whatever the CRD itself declares — there's no fixed list to check against. Only the built-in kinds this tool actually recognizes get checked against a known-correct apiVersion.
Why does a Service need a stricter name than everything else?
A Service name becomes part of a DNS record and an environment variable prefix injected into other pods, both of which historically couldn't start with a digit — so Service names follow RFC 1035 (must start with a letter) while most other Kubernetes object names follow the more permissive RFC 1123 (can start with a digit).