YAML on Kubernetes: 12 Config Mistakes That Break Deployments at 2 a.m.
By Safe Local Tools Editorial
YAML feels friendly until a two-space indent error takes down production. Kubernetes made YAML the default face of infrastructure, which means every engineer now edits a whitespace-sensitive format under pressure—often pasted from Stack Overflow, ChatGPT, or a Helm template with invisible characters.
This article catalogs twelve mistakes that survive code review, explains how the Kubernetes API actually parses manifests, and shows how to convert and inspect YAML locally in Safe Local Tools before kubectl apply sends it to a cluster.

YAML is a human interface, not a forgiving language
YAML 1.2 allows many scalar forms—quoted, unquoted, block literals—that JSON does not. That flexibility helps prose configs hurt machines:
yes/nomay become booleans in some parsers.0123can be interpreted as octal in older engines.- Multiline strings with accidental tabs break indentation rules.
Kubernetes uses YAML to JSON conversion on the server. If your file is valid YAML but maps to unexpected JSON types, you get subtle runtime behavior—not a syntax error.
Mistake 1 — Tabs instead of spaces
YAML forbids tab indentation for structure. Many editors silently insert tabs when you hit Tab on a laptop keyboard.
Symptom: found character that cannot start any token or parser points at a random line.
Fix: Editor “indent using spaces,” .editorconfig in repos, and pre-commit hooks that reject \t in *.yaml.
Mistake 2 — Inconsistent indent depth
Kubernetes lists use - items; sibling keys must align. An extra space under containers: nests a field under the wrong parent.
Symptom: Container env vars appear missing; probes attach to the wrong object.
Fix: Collapse unrelated branches in your IDE and enable YAML schema validation for Kubernetes if available.
Mistake 3 — Unquoted strings that become booleans or null
Examples that bite:
env:
- name: DEBUG
value: off # may become false in some parsersFix: Quote ambiguous scalars: value: "off".
Mistake 4 — Multiline shell scripts without block scalars
Pasting a args: script with : characters can confuse parsers.
Fix: Use | or > block scalars and quote where needed.
Mistake 5 — Duplicate keys (last wins silently)
Unlike JSON, some YAML loaders allow duplicate keys; the last wins without warning.
Symptom: You thought you set imagePullPolicy: Always but an earlier duplicate key was ignored—or overwritten.
Fix: Lint with strict mode; convert to JSON temporarily to spot duplicates.
Mistake 6 — Copy-paste from Helm without rendering
Templates left with {{ .Values.foo }} are not valid Kubernetes objects until templated.
Symptom: API server rejects unknown fields or literal braces appear in labels.
Fix: Always helm template or kubectl apply --dry-run=server in CI.
Mistake 7 — Wrong apiVersion / kind pairs
A valid YAML file can describe a resource the cluster does not understand.
Fix: Keep a version matrix per cluster; use discovery or kubectl api-resources.
Mistake 8 — Mega-manifests without separation
One 2,000-line file encourages accidental indent drift.
Fix: Kustomize overlays, split by concern (Deployment, Service, Ingress).
Mistake 9 — Secrets in plain YAML in git
Even if it “works,” it is a governance incident waiting for a scanner.
Fix: Sealed Secrets, SOPS, or external secret operators—never commit raw data: base64 blobs from prod.
Mistake 10 — Misunderstanding --- document separators
Multiple documents in one file are powerful; a missing separator merges unrelated objects.
Fix: Explicit --- between resources; limit files per logical release unit.
Mistake 11 — Numeric resource quantities as strings
Kubernetes expects quantities like 500m CPU and 512Mi memory as strings, not floats.
Symptom: Scheduling ignores limits or applies defaults.
Fix: Quote and validate against the quantity regex from Kubernetes docs.
Mistake 12 — Assuming JSON tools understand YAML anchors
Anchors (&id) and aliases (*id) do not exist in JSON. Converters may expand or reject them.
Fix: Prefer explicit duplication in committed manifests; use anchors only in local templating steps.
Why converting to JSON helps debugging
JSON is stricter: no comments (in pure JSON), no ambiguous scalars, no duplicate keys without parser errors. Round-tripping YAML → JSON → YAML through a careful tool exposes:
- Hidden type coercion
- Null vs empty string differences
- Arrays accidentally parsed as objects
Safe Local Tools converts YAML and JSON in the browser—handy when you cannot paste internal manifests into a cloud formatter.
A sane local workflow before apply
- Format and lint YAML in CI.
- Convert to JSON mentally or with a local tool to verify structure.
kubectl apply --dry-run=server -f manifest.yaml- Roll out canaries; watch events for field rejections.
Helm, Kustomize, and operator CRDs
Custom resources add OpenAPI schemas—another layer where YAML shape must match CRD definitions. A field valid in a Deployment may be invalid on your IngressRoute CRD.
Generate client-side validation when CRD tooling provides it; otherwise dry-run remains essential.
Security review habits
- Treat manifests like code: signed commits, required reviews.
- Scan for
hostPath,privileged: true, wildcard RBAC. - Pin images by digest in production, not only tags.
When ChatGPT writes your YAML
LLMs indent inconsistently and hallucinate apiVersions. Always run the same mechanical checks—never trust highlighted YAML in a chat bubble as deploy-ready.
CI patterns that catch YAML early
Add a job that runs on every pull request:
# Example: strict YAML parse + kubeconform (tools install omitted)
yamllint -c .yamllint manifest/
kubeconform -kubernetes-version 1.29.0 -summary manifest/kubeconform validates resources against OpenAPI schemas—closer to what the API server enforces than “it parsed as YAML.”
Store rendered manifests as build artifacts when using Helm so reviewers diff concrete YAML, not just template logic.
Working with Kustomize patches
Strategic merge patches can delete fields unintentionally when /$patch: delete appears. JSON patches are explicit but verbose. When debugging, render kustomize build overlays/prod to a temp file and convert to JSON to see the effective object the apiserver receives.
Linting tools worth trying
- yamllint for style and indentation
- kube-score for reliability recommendations (not schema validation)
- datree / policy engines for org rules (labels, probes required)
None replace kubectl apply --dry-run=server, but they shorten feedback loops in IDE.
ConfigMap and Secret volume mounts
YAML errors in mounted files can prevent pods from starting while the Deployment object itself applied cleanly. Test mounted configs with an init container that validates syntax before the main process starts.
Multi-cluster drift
Staging and production clusters at different minor versions accept different beta APIs. A manifest valid in staging may be rejected in prod—keep version skew documented next to cron and backup jobs, not only application code.
NetworkPolicy and Ingress YAML gotchas
Network policies use label selectors easy to mis-indent under spec. Ingress TLS blocks reference secrets by name—typo the secret name and the controller serves default certs silently. Convert to JSON to verify nesting before apply.
Resource quotas and limits
Accidentally placing resources under the wrong container in a multi-container pod starves sidecars. JSON view clarifies which container owns which limits.
Closing the loop with local conversion
YAML errors are rarely mystical; they are predictable whitespace and type issues amplified by Kubernetes’ strict JSON model underneath.
Before you paste another manifest into a cluster, convert and inspect it locally—Try the YAML ↔ JSON Converter →