Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Kubernetes & Helm By James Joyner IV · · 9 min read

Kubernetes Error Guide: 'strict decoding error: unknown field' — Fix Invalid Manifest Fields

Quick answer

Fix the 'strict decoding error: unknown field' from kubectl and Server-Side Apply: typos, wrong indentation nesting, deprecated fields, and CRD schema mismatches — with a full diagnostic workflow.

  • #kubernetes
  • #troubleshooting
  • #errors
  • #manifests
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

strict decoding error: unknown field means the API server (or kubectl in client-side validation) parsed your manifest, found a field it does not recognize for that object’s schema, and refused it. Since strict validation became the default, a misspelled or misplaced key is no longer silently dropped — it is an outright rejection.

You will see it in one of these forms:

error: error validating "deploy.yaml": error validating data: ValidationError(Deployment.spec.template.spec.containers[0]): unknown field "resource" in io.k8s.api.core.v1.Container
Error from server (BadRequest): error when creating "deploy.yaml": Deployment in version "v1" cannot be handled as a Deployment: strict decoding error: unknown field "spec.replias"

The two variants matter: the first (error validating) comes from kubectl’s client-side validation before the request is sent; the second (Error from server (BadRequest)) comes from the API server’s own strict decoder, which Server-Side Apply and newer clients use. Both mean the same thing — a key in your YAML/JSON does not exist in the target resource’s schema at the place you put it.

Symptoms

  • kubectl apply/create fails immediately with unknown field "<name>" and the object is never created or updated.
  • The error names the exact field and its schema path, e.g. Deployment.spec.template.spec.containers[0].
  • The same manifest may have “worked” on an older cluster (pre-strict) where unknown fields were dropped silently.
  • For CRDs, the field is real for one version but not the one you specified in apiVersion.
kubectl apply -f deploy.yaml
error: error validating "deploy.yaml": error validating data:
ValidationError(Deployment.spec): unknown field "replias" in io.k8s.api.apps.v1.DeploymentSpec;
if you choose to ignore these errors, turn validation off with --validate=false

Common Root Causes

1. A simple typo in a field name

The most common cause: replias instead of replicas, commands instead of command, enviroment instead of env. The schema path in the error points straight at the offending key.

ValidationError(Deployment.spec): unknown field "replias" in io.k8s.api.apps.v1.DeploymentSpec

Fix the spelling. kubectl explain deployment.spec lists the valid fields at that level.

2. Correct field, wrong nesting / indentation

The field name is spelled right but sits at the wrong level, so the decoder looks for it in a schema where it does not belong. A classic case is putting resources one level too high, or containers under spec instead of spec.template.spec.

spec:
  template:
    spec:
      containers:
        - name: app
          image: nginx
      resources:              # WRONG: resources belongs INSIDE the container
        limits:
          memory: 256Mi
ValidationError(Deployment.spec.template.spec): unknown field "resources" in io.k8s.api.core.v1.PodSpec

resources is a Container field, not a PodSpec field. Move it under the container.

3. Removed or renamed field in a newer API version

A field valid in an older schema was removed or renamed. Common examples: spec.selector shape changes, deprecated serviceAccount (use serviceAccountName), or beta fields that graduated and were renamed on promotion. On upgrade, a once-valid manifest suddenly rejects.

strict decoding error: unknown field "spec.serviceAccount"

Check the current schema with kubectl explain and update the manifest to the supported field.

4. CRD field that exists in a different version

For custom resources, each served version has its own schema. If you set apiVersion: example.com/v1beta1 but the field only exists in v1, strict decoding rejects it.

Error from server (BadRequest): ... strict decoding error: unknown field "spec.newTuning"

Confirm which versions the CRD serves and which contains the field:

kubectl get crd widgets.example.com -o jsonpath='{.spec.versions[*].name}'
kubectl explain widget.spec --api-version=example.com/v1

5. Wrong kind/apiVersion for the block you wrote

A manifest labeled as one kind but carrying another kind’s fields — e.g. a Service spec with containers, or a ConfigMap with spec. The decoder validates against the declared kind, so foreign fields are “unknown.”

ValidationError(Service.spec): unknown field "containers" in io.k8s.api.core.v1.ServiceSpec

Diagnostic Workflow

Step 1: Read the schema path in the error

The parenthetical path — ValidationError(Deployment.spec.template.spec.containers[0]) — tells you exactly which object and level the decoder was validating when it hit the unknown field. That is where to look, not the top of the file.

Step 2: Confirm the valid fields at that level

kubectl explain deployment.spec.template.spec.containers
kubectl explain deployment.spec.template.spec.containers.resources

kubectl explain prints the real schema for the exact path, so you can compare field names and nesting against your YAML.

Step 3: Validate without applying (dry run)

kubectl apply -f deploy.yaml --dry-run=server

Server-side dry run runs the same strict decoder the real apply uses (including CRD schemas and admission), so it reproduces the error safely without mutating anything.

Step 4: For CRDs, check which versions serve the field

kubectl get crd <name>.<group> -o yaml | grep -A3 'name:.*versions\|served'
kubectl explain <resource>.spec --api-version=<group>/<version>

Make sure your apiVersion matches the version whose schema actually contains the field.

Step 5: Diff against a known-good object

kubectl get deployment <existing> -o yaml > good.yaml
diff <(yq '.spec' good.yaml) <(yq '.spec' deploy.yaml)

Comparing your manifest to a live, accepted object of the same kind quickly surfaces a misnamed or misplaced field.

Example Root Cause Analysis

A pipeline that deployed fine last quarter starts failing after a cluster upgrade:

kubectl apply -f worker.yaml
Error from server (BadRequest): error when creating "worker.yaml":
Deployment in version "v1" cannot be handled as a Deployment:
strict decoding error: unknown field "spec.template.spec.containers[0].livenessProbe.timeout"

The schema path points at the container’s livenessProbe. Checking the real schema:

kubectl explain deployment.spec.template.spec.containers.livenessProbe
FIELDS:
  timeoutSeconds  <integer>
  ...

The field is timeoutSeconds, not timeout. On the old cluster (before strict decoding was the default) the unknown timeout key was silently dropped, so the probe quietly used the 1-second default and nobody noticed. After the upgrade, strict decoding rejects the whole manifest.

Fix — rename the field:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  timeoutSeconds: 5      # was: timeout: 5
kubectl apply -f worker.yaml --dry-run=server   # passes
kubectl apply -f worker.yaml

The deployment applies and the probe now gets the intended 5-second timeout — the bug the silent drop had been hiding.

Prevention Best Practices

  • Run kubectl apply --dry-run=server (or --server-side --dry-run=server) in CI on every manifest so unknown fields fail the pipeline, not production.
  • Use kubectl explain <kind>.<path> to confirm both the field name and its nesting level before writing it — the schema path is authoritative.
  • Lint manifests with a schema-aware tool (kubeconform / kubeval against the right Kubernetes version) so typos are caught locally.
  • After a cluster upgrade, re-validate manifests that “worked” before — strict decoding surfaces fields that were previously dropped silently and may hide bugs.
  • For CRDs, pin apiVersion to a version whose schema actually contains every field you set, and re-check when the operator is upgraded.
  • Never reach for --validate=false to make the error go away — it skips validation but the field is still ignored, reintroducing the silent-drop bug. See more in Kubernetes & Helm guides.

Quick Command Reference

# Reproduce the error safely against the real (server) decoder
kubectl apply -f manifest.yaml --dry-run=server

# Show valid fields + nesting for the exact schema path in the error
kubectl explain <kind>.<path>
kubectl explain deployment.spec.template.spec.containers.resources

# For CRDs: which versions are served, and the schema per version
kubectl get crd <name>.<group> -o jsonpath='{.spec.versions[*].name}'
kubectl explain <resource>.spec --api-version=<group>/<version>

# Diff your manifest against a known-good live object
kubectl get <kind> <existing> -o yaml > good.yaml
diff <(yq '.spec' good.yaml) <(yq '.spec' manifest.yaml)

# Schema-lint locally in CI (example)
kubeconform -strict -kubernetes-version 1.30.0 manifest.yaml

Conclusion

strict decoding error: unknown field means a key in your manifest does not exist in the target schema at the level you placed it. The usual root causes:

  1. A typo in the field name (replias, timeout vs timeoutSeconds).
  2. A correct field at the wrong nesting level (e.g. resources outside the container).
  3. A field removed or renamed in a newer API version, surfacing after an upgrade.
  4. A CRD field that only exists in a different served version than the apiVersion you set.
  5. A manifest whose kind does not match the fields it carries.

Read the schema path in the error, confirm the truth with kubectl explain, and reproduce with --dry-run=server. Strict decoding is a feature: the same typo that now fails loudly used to be dropped silently, often hiding a real misconfiguration. For turning a stack of apply errors into a prioritized fix list, the free incident assistant can help.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.