Common YAML Errors in Kubernetes and CI Pipelines (and How to Fix Them)

YAML powers the config layer of modern infrastructure — Kubernetes manifests, GitHub Actions workflows, docker-compose files, GitLab CI. Which means a single misplaced space can block a deployment at 6 pm on a Friday. The good news: YAML failures are highly repetitive. The same five or six mistakes account for nearly every broken pipeline. This guide catalogues them — with the exact error messages you will see in kubectl, Actions, and compose — and shows how to validate files before they ever reach production.

Error 1: Indentation Mistakes

The most common failure by far. One extra or missing space changes the structure of the document — sometimes producing a parse error, sometimes silently attaching a key to the wrong parent, which is worse because the file "works" but the value is ignored:

# BROKEN — resources is indented under image, not the container
spec:
  containers:
    - name: web
      image: nginx:1.27
        resources:          # <- 2 spaces too deep
          limits:
            memory: 512Mi

# kubectl: error converting YAML to JSON: yaml: line 6:
#          mapping values are not allowed in this context

# FIXED — resources aligns with name and image
    - name: web
      image: nginx:1.27
      resources:
        limits:
          memory: 512Mi

The silent variant: indenting env: at the pod level instead of the container level. Kubernetes ignores unknown fields in some paths, so your environment variables simply never appear. When a value "is not taking effect", check its indentation before anything else.

Error 2: Tab Characters

YAML forbids tabs in indentation, and the error message never says the word "tab":

yaml: line 12: found character that cannot start any token

# Find the invisible culprit:
grep -Pn "\t" deployment.yaml

# Fix in place (Linux/macOS):
sed -i 's/\t/  /g' deployment.yaml

Tabs sneak in when someone edits a file over SSH in a default vim, or copies a snippet from a terminal. Set your editor to insert spaces for .yml/.yamlfiles and add an .editorconfig so the whole team inherits the setting.

Error 3: Unquoted Strings Misparsed as Numbers and Booleans

YAML guesses types from unquoted values, and the guesses regularly break CI configs. Two famous cases: version numbers with trailing zeros become floats, and on/off/yes/no become booleans:

# GitHub Actions — the classic Python version bug
- uses: actions/setup-python@v5
  with:
    python-version: 3.10     # parsed as float 3.1 → installs 3.1!
    python-version: "3.10"   # correct — quoted string

# docker-compose — env values must be strings
environment:
  DEBUG: no                  # → boolean false, then coerced to "false"
  DEBUG: "no"                # correct

# Kubernetes annotation — floats not allowed
metadata:
  annotations:
    version: 1.20            # error: expected string, got float
    version: "1.20"          # correct

The rule: quote anything that is a string but does not look like one — versions, phone numbers, PIN codes with leading zeros, country codes, and every yes/no/on/off value. Pasting the block into a YAML to JSON converter shows you instantly which type the parser actually produced.

Error 4: Multi-Document Separators (---)

A single YAML file can hold multiple documents separated by --- on its own line — the standard way to ship a Deployment and Service together. Two common failures:

  • Missing separator — concatenating two manifests without --- merges them into one invalid document ("mapping key apiVersion already defined" or a schema error).
  • Indented separator--- must start at column zero; indented, it becomes a plain string value.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
# ...
---                    # column zero, its own line
apiVersion: v1
kind: Service
metadata:
  name: web-svc

Note for tooling authors: JSON.parse-style single-document parsers (like js-yaml's load) throw on multi-document files — use loadAll or split on the separator first.

Validate Before You Deploy: yamllint and kubectl --dry-run

Every error above is catchable before a commit ever triggers a pipeline. Layer these checks:

# 1. Lint syntax + style (tabs, indentation, duplicate keys)
pip install yamllint
yamllint deployment.yaml
# 12:1  error  syntax error: found character '\t' that cannot
#              start any token

# 2. Validate against the Kubernetes schema — client side
kubectl apply --dry-run=client -f deployment.yaml

# 3. Validate against the LIVE API server (webhooks, quotas)
kubectl apply --dry-run=server -f deployment.yaml

# 4. docker-compose has its own validator
docker compose config          # parses, resolves, prints final YAML

# 5. GitHub Actions — actionlint catches workflow-specific issues
actionlint .github/workflows/*.yml
  • yamllint catches pure YAML problems: tabs, bad indentation, duplicate keys, trailing spaces.
  • kubectl --dry-run=client checks the manifest against resource schemas without touching the cluster; =server also runs admission control.
  • docker compose config is the fastest way to see how compose interpreted your file, with variables resolved.
  • Wire yamllint and actionlint into a pre-commit hook or a cheap CI job so broken YAML never reaches the expensive pipeline stages.

A 60-Second Debugging Checklist

  • Read the line number in the error — the real mistake is usually on that line or the one above it.
  • Check for tabs: grep -Pn "\t" file.yaml.
  • Check sibling alignment around the reported line.
  • Quote suspicious values: versions, on/off/yes/no, anything with a colon or leading zero.
  • Confirm --- separators are at column zero.
  • Paste the file into a converter to see the parsed structure as JSON — misplaced nesting becomes obvious immediately.

Frequently Asked Questions

How do I validate a Kubernetes YAML file without applying it?

Run kubectl apply --dry-run=client -f file.yaml for a quick client-side syntax and schema check, or --dry-run=server to validate against the live API server including admission webhooks. Neither creates any resources. Add yamllint for style and indentation checks before that.

Why does my GitHub Actions workflow say "you may need to quote this value"?

YAML implicitly typed one of your values: on, off, yes, and no become booleans, and version-like numbers such as 3.10 become floats (3.1). Quote the value — python-version: "3.10" — to keep it a string. The bare word on as a top-level workflow key is a known quirk GitHub handles specially.

What does "found character that cannot start any token" mean in YAML?

It almost always means there is a tab character in your indentation. YAML forbids tabs for indentation. Find it with grep -P "\t" file.yaml, replace tabs with spaces, and set your editor to insert spaces for .yml files.

Try the Free YAML ↔ JSON Converter

Paste a broken manifest and instantly see how the parser reads it — wrong nesting, surprise booleans, and float-ified versions all become visible in the JSON output. No signup, no cost.

Related articles