Skip to content
Intellira
Kuberneteshigh severity

PVCPending

A PVC stuck Pending means no volume bound it: missing StorageClass, WaitForFirstConsumer, no provisioner, no matching PV, or access-mode mismatch.

Written by Intellira Engineering, Editorial team

What a Pending PVC means

A PersistentVolumeClaim sits in Pending because nothing has bound a PersistentVolume to it. A control loop in the control plane watches for new PVCs and "finds a matching PV (if possible), and binds them together"; until that match exists, the claim remains unbound. A PVC binds in one of two ways: an existing PV that satisfies the claim (static), or a StorageClass that provisions one on demand (dynamic). When neither happens, the claim stays Pending and any Pod that mounts it cannot start.

The single most useful command is kubectl describe pvc — read its Events. The event message tells you which of the mechanisms below you are in, and they do not share a fix.

One distinction first, because it changes everything: a Pending PVC has never bound, so there is nothing to mount. That is not the same as a Pod stuck in ContainerCreating, where an already-bound volume fails to attach or mount on the node, nor the same as a Pod that will not schedule. Confirm the PVC is the thing that is stuck before you touch the workload.

Diagnose it

kubectl get pvc -n <namespace>
kubectl describe pvc <claim> -n <namespace>
kubectl get storageclass
kubectl get pv

kubectl get pvc shows STATUS Pending and an empty VOLUME column. The decisive signal is the Events block from kubectl describe pvc. Match the message:

# No StorageClass / no default to provision from
no persistent volumes available for this claim and no storage class is set

# WaitForFirstConsumer — this is NORMAL, not a failure
waiting for first consumer to be created before binding

# Provisioner missing or name typo — nothing is listening
storageclass.storage.k8s.io "fast-ssd" not found
# or the PVC has a provisioner annotation but no controller acts on it

# Dynamic provisioning attempted but failed (quota, capacity, topology)
failed to provision volume with StorageClass "...": ...

# Static binding: no PV matches size / access mode / class
no persistent volumes available for this claim

kubectl get storageclass tells you whether a class exists and which one is marked (default). kubectl get pv tells you whether any static PV is Available to bind. Hold those three outputs side by side and the cause is usually obvious.

Causes, and how to fix each

Each mechanism is independent. Identify the event, then apply only that fix.

1. No StorageClass named, or no default StorageClass set

If a PVC omits storageClassName, Kubernetes uses the default StorageClass — the one annotated storageclass.kubernetes.io/is-default-class: "true". With no default and no explicit class, dynamic provisioning never starts and the claim stays Pending. A PVC that requests the class "" deliberately disables dynamic provisioning for itself.

  • Diagnose: kubectl get storageclass shows no row marked (default), or the storageClassName in your PVC names a class that does not exist. The event reads no persistent volumes available for this claim and no storage class is set.
  • Fix: mark one class default with the storageclass.kubernetes.io/is-default-class annotation, or add an explicit storageClassName to the PVC. Note the blast radius: only have one class marked default — if two are, Kubernetes "uses the most recently created default StorageClass".
  • Newer clusters: since Kubernetes v1.26 the retroactive default StorageClass feature assigns a default to PVCs that were created before any default existed; older clusters leave them "stuck" Pending forever and you must recreate or patch the claim.

2. WaitForFirstConsumer — Pending is the intended state

This is the one case where Pending is correct. A StorageClass with volumeBindingMode: WaitForFirstConsumer "will delay the binding and provisioning of a PersistentVolume until a Pod using the PersistentVolumeClaim is created." Until a Pod that mounts the claim is scheduled, the PVC is supposed to stay Pending so the volume lands in the right topology.

  • Diagnose: kubectl describe pvc event reads waiting for first consumer to be created before binding. kubectl get storageclass <name> -o yaml shows volumeBindingMode: WaitForFirstConsumer. If no Pod references the claim yet, there is no bug.
  • Fix: schedule a Pod that mounts the PVC — binding follows. If a Pod already exists but the PVC still will not bind, the consumer cannot schedule (see causes 6 and 7), or the Pod uses nodeName: the docs warn that with WaitForFirstConsumer, using nodeName bypasses the scheduler and "PVC will remain in pending state". Remove nodeName and use node affinity instead.

3. No CSI driver / provisioner installed, or a provisioner-name typo

A StorageClass must name a provisioner — "this field must be specified" — and for an external CSI provisioner, "a CSI driver must be deployed on your cluster to use a csi volume" (CSI volumes). If the driver was never installed, or the provisioner string is misspelled, nothing acts on the claim and it stays Pending with no error — because no controller is listening for it.

  • Diagnose: kubectl get storageclass shows the class, but no provisioning event ever appears on kubectl describe pvc (silence, not failure). Confirm the CSI controller is running, for example kubectl get pods -n kube-system | grep csi, and compare the StorageClass provisioner value against the driver's real name (for example ebs.csi.aws.com or pd.csi.storage.gke.io).
  • Fix: install the CSI driver, or correct the provisioner field to the driver's exact name. A StorageClass is immutable, so fixing a typo means deleting and recreating the class (and any PVC that referenced the wrong one).

4. Static provisioning — no PersistentVolume matches the claim

With static provisioning an administrator pre-creates PVs. The claim binds only to a PV that satisfies size, access modes, and storageClassName. The docs are explicit: "a cluster provisioned with many 50Gi PVs would not match a PVC requesting 100Gi" (binding), and claims "will remain unbound indefinitely if a matching volume does not exist."

  • Diagnose: kubectl get pv shows PVs that are Available but none whose capacity is equal to or greater than the request, whose access modes cover the request, and whose storageClassName matches. The event reads no persistent volumes available for this claim.
  • Fix: create a PV that matches all three of size (at least the requested capacity), access modes, and storageClassName, or shrink the PVC request to fit an existing PV.

5. Access-mode mismatch (RWO vs RWX)

The four access modes are ReadWriteOnce, ReadOnlyMany, ReadWriteMany, and ReadWriteOncePod. Not every backend supports every mode — block storage like AWS EBS or GCE PD is typically ReadWriteOnce only, while ReadWriteMany usually needs a shared filesystem such as NFS or a clustered file system. If the PVC requests RWX from a backend that only offers RWO, no PV matches and provisioning fails.

  • Diagnose: compare the PVC accessModes with what the backend supports. For static PVs, kubectl get pv shows the PV ACCESS MODES column; for dynamic, check the driver's documentation. The event is no persistent volumes available for this claim or a failed to provision message naming the mode.
  • Fix: request a mode the backend supports (use RWO for single-node block volumes), or switch to a backend that genuinely supports RWX. Do not assume a CSI driver supports RWX just because the API accepts the field — the API validates syntax, not capability.

6. Topology / zone mismatch

A block volume lives in one availability zone. With Immediate binding the docs warn that PVs are "bound or provisioned without knowledge of the Pod's scheduling requirements. This may result in unschedulable Pods" — the volume is stranded in a zone the Pod cannot reach, so either the PVC provisions into the wrong zone or the consumer Pod cannot schedule.

  • Diagnose: the volume provisioned but the Pod that mounts it stays unschedulable; compare the node zone labels with the volume's zone. For static PVs, an allowedTopologies/node-affinity mismatch keeps the claim from binding to a usable PV.
  • Fix: prefer WaitForFirstConsumer so the volume is provisioned in the zone the Pod is scheduled to, rather than provisioned first and stranded. Where you must pin zones, set allowedTopologies on the StorageClass.

7. Quota or capacity — the provisioner cannot satisfy the request

Dynamic provisioning can fail when the backend cannot create a volume of the requested size: a cloud account quota, a storage-pool capacity limit, or a per-volume size ceiling. The provisioner attempts, fails, and the PVC stays Pending.

  • Diagnose: the event reads failed to provision volume with StorageClass "...": followed by the backend error (quota exceeded, insufficient capacity, invalid size). The provisioner retries, so the event repeats.
  • Fix: raise the backend quota or free capacity, or reduce the requested size to within limits. The provisioner retries automatically once the backend can satisfy the request — you do not need to recreate the PVC unless its requested size is itself invalid.

Fix it

  1. Run kubectl describe pvc <claim> -n <namespace> and read the first event.
  2. Classify it: no/typo StorageClass, WaitForFirstConsumer (normal), missing provisioner, no matching static PV, access-mode mismatch, topology mismatch, or quota/capacity.
  3. If the event is waiting for first consumer, stop — schedule a Pod that mounts the claim and binding follows. Nothing else is wrong.
  4. Otherwise apply the single matching fix. Remember a StorageClass is immutable: fixing a provisioner or binding-mode typo means recreating the class and the affected PVCs.
  5. Confirm the PVC reaches Bound with kubectl get pvc before expecting the Pod to mount it. Binding must succeed before attach/mount even begins.

How Intellira diagnoses this

Intellira reads the PVC events through the read-only Kubernetes MCP server and classifies the stall on the first pass — separating the one benign case (WaitForFirstConsumer waiting for a consumer) from the genuine faults (no default StorageClass, missing or misnamed provisioner, no matching PV, access-mode or topology mismatch, quota). It then correlates the StorageClass and PVC manifests against the change that introduced them: the ArgoCD sync or the Bitbucket commit that added the claim, renamed the storageClassName, or flipped volumeBindingMode. That turns "PVC is Pending" into "this commit set storageClassName: fast-ssd, but no StorageClass by that name exists in the cluster." The agent never deletes or recreates storage objects — it points you at the binding decision and the change that broke it, and leaves the apply to you.

Sources

By Intellira Engineering. AI-assisted draft; claims cited inline; last verified 2026-06-02. Pending technical review.

Frequently asked questions

Is a Pending PVC always a bug?
No. If the PVC uses a StorageClass with volumeBindingMode WaitForFirstConsumer, the PVC is supposed to stay Pending until a Pod that references it is scheduled. kubectl describe pvc shows the event "waiting for first consumer to be created before binding". That is the system working as designed, not a fault.
What is the difference between a Pending PVC and a Pod stuck in ContainerCreating?
A Pending PVC has never bound to a volume, so there is nothing to mount yet. A Pod in ContainerCreating usually has an already-bound volume that will not attach or mount on the node. They live at different stages: binding versus attach/mount. Read the PVC status first, then the Pod events.
Why does my PVC say Pending right after I created the cluster?
Most often there is no default StorageClass, so a PVC with no storageClassName has nothing to provision it. Run kubectl get storageclass; if none is marked (default), either set one or add storageClassName to the claim.

Related errors

Find the root cause of PVCPending on your stack

Connect read-only and Intellira correlates the change behind it across Bitbucket, Jenkins, ArgoCD and Kubernetes — with the evidence to prove it.