# kubectl annotate: Usage, Options & Common CI Errors

> kubectl annotate attaches non-identifying metadata to resources. Annotations vs labels, and the change-cause annotation pattern for rollout history in CI.

Source: https://latchkey.dev/learn/command-reference/kubectl-annotate  
Updated: 2026-06-25

Attach metadata that tools read but selectors ignore.

kubectl annotate sets free-form key/value metadata on an object. Unlike labels, annotations are not used for selection - they carry information for controllers, tooling, and humans, including the change-cause shown in rollout history.

## What it does

kubectl annotate RESOURCE NAME key=value adds an annotation; key- removes it and --overwrite replaces an existing one - identical ergonomics to kubectl label. Annotations have no value-format restrictions and a generous size budget, so they hold things labels cannot (URLs, JSON, descriptions).

## Common usage

```Terminal
kubectl annotate deploy/web kubernetes.io/change-cause="deploy ${GIT_SHA}"
kubectl annotate svc/web prometheus.io/scrape="true"
kubectl annotate pod my-pod description="debug fixture" --overwrite
kubectl annotate pod my-pod description-       # remove
```

## Common errors in CI

Like label, re-running without --overwrite fails with "already has a value ... and --overwrite is false" - add --overwrite for idempotent pipelines. The total annotations payload is capped at 256 KB; stuffing a large file into an annotation triggers "metadata.annotations: Too long". Note that kubectl apply stores its prior state in the kubectl.kubernetes.io/last-applied-configuration annotation, so very large manifests can approach that limit - prefer --server-side apply, which does not use that annotation.

## 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.

```Terminal
# 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
```

> Always set `--request-timeout` in CI. Without it an unreachable API server hangs until the job times out, which turns a thirty-second failure into a twenty-minute one.

## FAQ

### kubectl annotate: Usage, Options & Common CI Errors?

kubectl annotate sets free-form key/value metadata on an object. Unlike labels, annotations are not used for selection - they carry information for controllers, tooling, and humans, including the change-cause shown in rollout history.

### What it does?

kubectl annotate RESOURCE NAME key=value adds an annotation; key- removes it and --overwrite replaces an existing one - identical ergonomics to kubectl label. Annotations have no value-format restrictions and a generous size budget, so they hold things labels cannot (URLs, JSON, descriptions).

### Common errors in CI?

Like label, re-running without --overwrite fails with "already has a value ... and --overwrite is false" - add --overwrite for idempotent pipelines. The total annotations payload is capped at 256 KB; stuffing a large file into an annotation triggers "metadata.annotations: Too long".

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
