Linux  ·  high  ·  Containers & Kubernetes

A PersistentVolumeClaim stays Pending and the pod never starts

Nothing has satisfied the claim — no storage class, no matching volume, or a provisioner that cannot do what was asked.

What you see

The pod sits in Pending. Describing it says the claim is not bound; describing the claim says why.

What is actually wrong

No default storage class, an access mode the backend does not support, a zone mismatch, or the provisioner failing at the storage layer.

Codes and articles

PersistentVolumeClaim is not boundwaiting for first consumerno persistent volumes availableprovisioning failedFailedAttachVolume

Fixes (2)

Understand the normal case before treating it as a fault
Root shell15 minuteslow riskreversible

"waiting for first consumer to be created before binding".

  1. This message is usually not an error. A storage class with WaitForFirstConsumer deliberately delays binding until a pod is scheduled, so the volume is created in the right zone.

    Shell
    kubectl get storageclass -o custom-columns=NAME:.metadata.name,MODE:.volumeBindingMode,PROVISIONER:.provisioner

    Chasing this as a storage fault is a common waste of an afternoon. If no pod is using the claim yet, Pending is the correct state and it will bind the moment one is scheduled.

  2. Check whether a pod actually references it.

    Shell
    kubectl get pods -o json | jq -r '.items[] | select(.spec.volumes[]?.persistentVolumeClaim.claimName=="myclaim") | .metadata.name'
  3. If a pod does reference it and it is still Pending, look at why the pod cannot be scheduled — that is the real blocker.

    Shell
    kubectl describe pod mypod | sed -n '/Events:/,$p'
  4. Check node affinity and zone constraints, which commonly make a volume unschedulable.

    Shell
    kubectl get nodes -L topology.kubernetes.io/zone
Confirm it workedThe claim binds once a pod is scheduled.
Shell
kubectl get pvc
If you need to undo itNothing was changed.
Fix the storage class or the access mode
Root shell30 minutesmedium riskreversible

No class, or provisioning fails.

  1. Check whether a default storage class exists. A claim with no class specified and no default will wait forever.

    Shell
    kubectl get storageclasskubectl get sc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}{"\n"}{end}'
  2. Mark one as default if none is.

    Shell
    kubectl patch storageclass standard -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  3. Check the access mode is one the backend supports. Most block storage supports ReadWriteOnce only — asking for ReadWriteMany fails silently at provisioning.

    Shell
    kubectl get pvc myclaim -o jsonpath='{.spec.accessModes}'

    ReadWriteMany requires a shared filesystem such as NFS or CephFS. Requesting it from a cloud block-storage provisioner produces a claim that never binds with an error that does not mention access modes at all.

  4. Read the provisioner's own events, which carry the underlying storage error.

    Shell
    kubectl describe pvc myclaim | sed -n '/Events:/,$p'kubectl -n kube-system logs -l app=csi-provisioner --tail=50
  5. Check quota at the storage backend — a cloud account at its volume limit fails here.

Confirm it workedThe claim binds and the pod starts with the volume mounted.
Shell
kubectl get pvc,pv; kubectl describe pod mypod | grep -A5 Mounts
If you need to undo itRemove the default-class annotation if it was added in error.

Where this stops. This write-up was written and checked by hand. It says what each step changes, how to confirm it worked and how to reverse it, and anything destructive is flagged before you reach it. If it does not match what your machine is doing, search the Support Centre for the exact code or message — and when something needs a person, get in touch.