kubectl patch --type=json: Usage, Options & Common CI Errors
Apply precise add/replace/remove operations at exact JSON paths.
kubectl patch --type=json applies an RFC 6902 JSON Patch: an ordered list of add/replace/remove/test operations against explicit paths. It is the precise tool when strategic-merge cannot express the edit, especially on custom resources.
What it does
kubectl patch RESOURCE NAME --type=json -p '[...ops...]' runs each operation in order. op is add, replace, remove, copy, move, or test; path is a JSON Pointer where / separates keys and ~1 escapes a literal / (and ~0 a ~). Array indices are numeric, and a trailing - appends to an array.
Common usage
kubectl patch deploy/web --type=json \
-p '[{"op":"replace","path":"/spec/replicas","value":3}]'
kubectl patch deploy/web --type=json \
-p '[{"op":"add","path":"/spec/template/metadata/labels/tier","value":"web"}]'
kubectl patch ingress/web --type=json \
-p '[{"op":"remove","path":"/spec/rules/0/http/paths/1"}]'Common errors in CI
A replace or remove against a path that does not exist fails with "the server rejected our request" / "add operation does not apply: doc is missing path" - use add to create the parent first, or guard that the path exists. Annotation/label keys with dots and slashes must be escaped: /metadata/annotations/example.com~1foo for the key example.com/foo. JSON-patch is the safe choice for CRDs (which have no strategic-merge metadata) where strategic patches silently misbehave. Operations apply in order, so an add that a later remove depends on must come first.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes