How to validate a Kubernetes manifest in 10 seconds without kubectl
published
If you have ever applied a Kubernetes manifest only to watch kubectl reject it with a cryptic error converting YAML to JSON, you know the value of a fast pre-flight check. This post walks through a browser-only workflow that catches syntax errors, type-coercion bugs, and structural drift in under 10 seconds — without installing anything, without running a cluster, and without uploading your manifest to a third-party validator.
The 3-step check
- Paste your YAML into the JSON ↔ YAML converter and switch to YAML → JSON mode.
- Read the error, if any. The parser surfaces line/column for malformed YAML directly.
- Copy the JSON output to the JSON formatter to double-check structure and run optional sort-keys for diffing.
That’s it. Everything client-side. The whole loop fits in a coffee break.
What this catches
YAML syntax errors that kubectl apply reports cryptically
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
spec:
replicas: 3
selector:
matchLabels:
app: demo
The matchLabels line is indented one space short. kubectl says:
error: error parsing manifest.yaml: error converting YAML to JSON: yaml: line 8: did not find expected key
The JSON ↔ YAML converter says:
Line 8, column 3 — bad indentation of a mapping entry
Same problem, plain-English message, no cluster round-trip.
The Norway problem and other YAML 1.1 coercions
This is the classic foot-gun. In YAML 1.1, the following:
country: NO
…parses as country: false. Because NO, no, N, n, OFF, off, false, and FALSE are all booleans in the 1.1 spec. Same for YES, ON, TRUE, etc.
Kubernetes manifests are usually parsed with YAML 1.2 + the JSON-compatible schema, which strips these aliases. But:
- Helm’s templating engine uses Go’s
yaml.v2library, which still honors most YAML 1.1 booleans. - Argo Workflows, several Kustomize patches, and older CI pipelines also bite.
The converter uses YAML 1.2 with the JSON-compatible schema specifically to avoid this. If country: NO round-trips back as the string "NO", you’re safe across modern parsers. If it round-trips as false, the YAML library Kubernetes uses may still treat it as a boolean depending on the cluster’s API server version.
Defensive habit: quote any all-caps string in YAML. country: "NO" works everywhere.
Floats where you wanted strings
version: 1.0
This parses as the float 1, which serializes back as "1". Your image tag silently lost its .0.
version: "1.0"
This parses as the string "1.0" and round-trips correctly.
The converter’s quoting strategy on JSON → YAML quotes any string that would otherwise be coerced — numeric-looking, boolean-looking, null-looking. Round-tripping is safe by default.
Octal numbers
timeout: 010
YAML 1.1 reads this as octal 8. YAML 1.2 reads it as the string "010". Different parsers, different answers. Always quote.
What kubectl --dry-run=client does not catch that this workflow does
kubectl --dry-run=client -o yaml -f manifest.yaml validates schema against the server’s CRDs. It catches:
- Missing required fields
- Wrong field types after coercion
- Unknown fields (with strict mode)
It does not catch:
- Two manifests with the same effective shape but different key order (diffing config drift)
- Round-trip coercions where the YAML you wrote and the YAML the server stores differ
- Pure formatting differences
The browser workflow handles all three: convert both manifests to JSON, sort keys recursively, then diff the results in JSON-aware mode. Pure formatting drift collapses to zero.
A 30-second drift check
You’re debugging why staging works but prod doesn’t. Both manifests are 200 lines of YAML.
- Paste prod manifest into JSON ↔ YAML, JSON output → copy.
- Paste staging manifest into JSON ↔ YAML, JSON output → copy.
- Open the diff checker, paste prod on the left, staging on the right, switch to JSON-aware mode.
- Read the structural diff. Keys reordered between files? Invisible. Real value differences? Highlighted.
The whole process is faster than waiting for kubectl diff to round-trip through the API server, and works on manifests that aren’t even applied yet.
When YAML really does need a server check
The browser workflow is for syntax, structure, and round-trip safety. It cannot validate:
kubectl explainsemantics (isspec.template.spec.containers[].imagePullPolicyactually a recognized field for this resource version?)- CRD-specific validation rules
- Admission webhook side-effects (e.g., a mutating webhook injecting an init container)
- RBAC permissions
For those you still need kubectl --dry-run=server or a tool like kubeconform running offline against bundled OpenAPI schemas. But 80% of “the manifest is broken” errors are caught by the 10-second loop above.
Privacy notes
The converter, formatter, and diff checker all run entirely in your browser tab. Manifests can contain secrets — secret names, registry credentials, internal service URLs — that you probably don’t want pasted into a random online validator. With browser-only tools the input never leaves your device. Verify with DevTools → Network: nothing fires after the page loads.
Tooling
- JSON ↔ YAML Converter — bidirectional, YAML 1.2 schema, surfaces line/column on parse failure.
- JSON Formatter & Error Reviewer — sort keys, pretty-print, JSONC mode.
- Diff Checker — line, word, char, and JSON-aware modes; side-by-side or unified.
All three are free, client-side, no signup, no upload.